Layout: Vertically-aligned links next to div - css

Sample code:
a {
background: tan;
}
div {
width: 100px;
height: 200px;
background: green;
}
Link 1
This is link 2.
3rd
<div></div>
This is the effect I wish to achieve:
It's easy to vertically align the anchor elements by something like display: block, but I have no idea how to put the <div> element next to them.
Note 1: The above is just a sample code. My actual links can be any width.
Note 2: The <div> needs to be the anchors' next sibling. It can be any height.

I would go for a grid:
You can set it to adapt automatically to the inner dimensions.
You only need to set some row and column properties to locate the inner elements
a {
background: tan;
grid-column: 1;
}
a:nth-child(2) {
grid-row: 2;
}
#mydiv {
width: 100px;
height: 200px;
background: green;
grid-column: 2;
grid-row: 1 / 5;
}
.container {
display: grid;
grid-template-columns: max-content auto;
grid-template-rows: auto auto auto 1fr;
}
<div class="container">
Link 1
This is link 2.
3rd
<div id="mydiv"></div>
</div>
It will work also in the case of a huge margin bottom on anchors
a {
background: tan;
grid-column: 1;
margin-bottom: 200px;
}
a:nth-child(2) {
grid-row: 2;
}
#mydiv {
width: 100px;
height: 200px;
background: green;
grid-column: 2;
grid-row: 1 / 5;
}
.container {
display: grid;
grid-template-columns: max-content auto;
grid-template-rows: auto auto auto 1fr;
}
<div class="container">
Link 1
This is link 2, now longer.
3rd
<div id="mydiv"></div>
</div>

Try this solution
First we need two columns, one column for links, second for the DIV
tag. I preferred to take the grid.
Used fit-content to for fit background on links.
The DIV needs to set as position: absolute, because without
absolute position, div will be resize only the first row in the
second column.
For adjustment width of the div, i was create a variable. This
resizes both the second column of the grid and width of the div.
:root {
--second-column: 100px;
}
body {
width: min-content;
display: grid;
grid-template-columns: max-content var(--second-column);
grid-auto-rows: min-content;
row-gap: 1rem;
column-gap: 2rem;
background-color: hsl(201, 27%, 10%);
position: relative;
}
a {
grid-column: 1;
width: fit-content;
background: tan;
}
div {
grid-column: 2;
grid-row: 1 / -1;
width: var(--second-column);
height: 200px;
position: absolute;
background: green;
}
Link 1
This is link 2.
3rd
<div></div>

The good old float
a {
background: tan;
margin: 5px;
/* all the links at the left
above each other */
float: left;
clear: left;
}
div {
width: 100px;
height: 200px;
background: green;
overflow: auto; /* do not overlap the links and stay at the right */
}
Link 1
This is link 2.
3rd
<div></div>

Here, check this out.
a {
background: tan;
display: block;
margin-bottom: 5px;
}
div {
width: 100px;
height: 100px;
display: inline-block;
vertical-align: top;
}
div.div2 {
background: green;
}
<div>
Link 1
This is link 2.
3rd
</div>
<div class="div2"></div>

a {
background: tan;
}
#child-1 {
display: flex;
flex-direction: column;
align-items: flex-start;
}
#child-2 {
width: 100px;
height: 100px;
background: green;
}
#parent {
display: flex;
}
<div id="parent">
<div id="child-1">
Link 1
This is link 2.
3rd
</div>
<div id="child-2"></div>
</div>

Easiest is to use float:left; on all links as mentioned before. but we probably don't really like float for situations where we also might want to do more complex stuff.
Also you might want to add markup for semantic purposes anyway (like <nav> for the links). The only reason I could make up for the links having to be siblings of the div is javaScript, and bet it will be possible to tune it more performant with slightly more markup around.
To do so you might want to have a look at flexbox like so:
.container{
display:flex;
flex-direction: row;
justify-content: space-between;
border: 1px solid blue;
}
ul{
flex: 1 1 auto;
align-self: flex-start;
display:flex;
flex-direction: column;
padding: 0;
margin: 0;
}
li{
border: 1px solid red;
flex: 1 1 auto;
}
a {
background: tan;
}
div.main {
flex: 0 1 100px;
height: 200px;
background: green;
}
<div class="container">
<ul>
<li>Link 1</li>
<li>This is link 2.</li>
<li>3rd</li>
</ul>
<div class="main">lore ipsum</div>
</div>
No matter how you do it you need a little more markup to solve this if you want a generic answer but not use float. There might be a way around this in certain situations but there is none in a genric scenario. That is if you do not allow javaScript to fix it (which would most likely be an unresasonable solution).
The li of cause is unnecessary for your question but in general its a good idea not to position a tags directly but to wrap them. a-tags also tend to have unforeseen bugs when positioned with flexbox.
The surrounding div.container could be the documents body tag instead. Then you could simplify to:
body{
display:flex;
flex-direction: row;
justify-content: space-between;
border: 1px solid blue;
}
nav{
flex: 1 1 auto;
align-self: flex-start;
display:flex;
flex-direction: column;
padding: 0;
margin: 0;
}
a {
background: tan;
}
div {
flex: 0 1 100px;
height: 200px;
background: green;
}
<nav>
Link 1
This is link 2.
3rd
</nav>
<div>lorem ipsum</div>

i used and change this solution inside my answer.
div element gives links higtht and stays after theme.
body {
display: grid;
grid-template-columns: 1fr max-content;
width: max-content;
}
a {
background: tan;
margin: 50px;
grid-column: 1;
width: fit-content;
}
div {
width: 100px;
min-height: 200px;
background: green;
grid-column: 2;
grid-row: 1 / 9999;
}
Link 1
This is link 2.
3rd
4th long long and too long link. f it Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptate nostrum quibusdam cupiditate deleniti possimus sit!
<div></div>

You have to use position property and display inline-block or you can use display flex
a {
background: tan;
display:block;
margin-bottom: 16px;
width: 100px;
}
.main {
width: 100px;
height: 100px;
background: green;
position: absolute;
left: 20%;
top: 8px;
}
Link 1
This is link 2.
3rd
<div class="main"></div>

Use CSS clear Property to make anchor elements not allowed to Float on the left side in relation to other element
Using CSS Overflow, the overflow of the div is clipped, and the rest of the content will be invisible, I set it to use hidden, you can also use auto, but auto adds scrollbars only when necessary
a {
background: tan;
float: left;
clear: left;
}
div {
width: 100px;
height: 200px;
background: green;
overflow: hidden;
}
Link 1
This is link 2.
3rd
This is a long string for testing
<div></div>

Flexbox seems to be a good approach. Wrap all the links (anchor tags) in a div element and then wrap that div along with the other div you want to be side by side in another div. See below code example:
CSS
.parentDiv {
display: flex;
}
.links {
display: flex;
flex-direction: column;
}
a {
background: tan;
}
.otherDiv {
width: 100px;
height: 200px;
background: green;
}
HTML
<div class="parentDiv">
<div class="links">
Link 1
This is link 2.
3rd
</div>
<div class="otherDiv"></div>
</div>

As a fan of using flexbox, I came up with this approach
HTML
<div class="parent">
<div>
Link 1
This is link 2.
3rd
</div>
<div></div>
</div>
CSS
a {
background: tan;
}
.parent {
display: flex;
}
.parent div:first-child {
display: flex;
flex-direction: column;
margin-right: 20px;
}
.parent div:first-child a {
margin-bottom: 10px;
}
.parent div:last-child {
width: 100px;
height: 200px;
background: green;
}

Just wrapper your content with one parent class with Flex property and it's done. It will solve your problem.
Refer to below snippet code
.parent {
display: flex;
}
a {
background: tan;
}
.otherclass {
width: 100px;
height: auto;
background: green;
flex: 0 0 1;
}
<div class="parent">
<ul>
<li>
Link 1</li>
<li>
This is link 2.</li>
<li>
3rd</li>
<li>
Link 1</li>
<li>
This is link 2.</li>
<li>
3rd</li>
</ul>
<div class='otherclass'></div>
</div>

Related

Grid area not reducing its width even by using fr

Here, I have a red container, yellow container, and a navbar component.
When the navbar component(blue) is present, I want to reduce the width of both the red and yellow container so that it doesn't overlap.
I tried using fr so that red and blue container takes only the available space but it doesn't seem to work.
.flexrow {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.pagetoplayout {
display: grid;
flex-grow: 1;
grid-template-columns: 70fr 30fr;
grid-template-rows: auto auto;
overflow: auto;
grid-template-areas:
'tophalf tophalf'
'bottomside bottomside';
}
.tophalf{
grid-area: tophalf;
background: red;
}
.bookingside {
grid-area: bottomside;
background: yellow;
}
.navbar--visible {
width: 500px;
position: absolute;
top: 0;
right: 0;
display: block;
background-color: var(--color-black);
overflow: auto;
padding: 30px 20px;
opacity: 1;
background: blue;
opacity:0.8;
}
<div class="flexrow">
<div class="pagetoplayout">
<div class="tophalf">Container 1</div>
<div class="bookingside">Container 2 </div>
</div>
<div class="navbar--visible">
asa
</div>
<div>
Your navbar(blue) has position: absolute; applied which removes it from layout calculations. That's the reason it is shown over top of the other elements and doesn't affect the layout.

Grid layout but avoid space distribute equally

I'm trying to use the grid layout for two columns in one row which can be easily achieved by flex. I have to create one more div for flex but the grid doesn't need one more div.
The problem with the grid is that it will divide the width space by 2 (cannot align to start/left) and that's not what I want, please refer to the first example below and you will understand.
Is there any way to use the grid in this situation but we can align the items to the left like in the second example?
#main-1 {
display: grid;
gap: 30px;
grid-teplate-column: repeat(2, minmax(0, 1fr));
}
.test-1 {
background-color: orange;
grid-area: span 1 / span 2;
}
.test-2 {
background-color: gray;
width: 150px;
}
#main-2 {
display: flex;
gap: 30px;
margin-top: 30px;
}
.test-3 {
background-color: orange;
width: 100%;
}
.test-4 {
background-color: gray;
width: 150px;
}
.test-1,
.test-2,
.test-3,
.test-4 {
height: 60px;
}
<h1>Grid</h1>
<div id="main-1">
<div class="test-1"></div>
<div class="test-2"></div>
<div class="test-2"></div>
</div>
<h1 style="margin:30px 0 0 0;padding-top:15px;border-top: 3px solid #000;">Flex</h1>
<p style="margin:0 0 30px 0;">This is the desired layout but with one more extra div</p>
<div>
<div class="test-3"></div>
<div id="main-2">
<div class="test-4"></div>
<div class="test-4"></div>
</div>
</div>
Edited
Inline-block might work but we cannot control how many items should be on each row. Imagine the width of the first div .first is dynamic and we do not know how wide it would be(but I will make it 30px for illustration). Now the desired layout should be only one .first and one .second on each row.
By inline-block it would appear that now each row is one .first, one .second, and one .first. Check out the example below. Because we cannot control the amount like grid on each row.
#main {
width: 120px;
}
.first,
.second {
display: inline-block;
height: 60px;
}
.first {
background-color: orange;
width: 30px;
}
<div id="main">
<div class="first"></div>
<p class="second">hhhhhh</p>
<div class="first"></div>
<p class="second">hhhhhh</p>
<div class="first"></div>
<p class="second">hhhhhh</p>
</div>
Define the columns as auto and keep only one at 1fr then you can align to the left.
#main-1 {
display: grid;
gap: 30px;
/* update "5" based on your needs */
grid-template-columns: repeat(5,auto) 1fr;
justify-content: left; /* align to left */
}
.test-1 {
background-color: orange;
grid-column: 1/-1; /* take all the columns */
}
.test-2 {
background-color: gray;
width: 150px;
}
#main-2 {
display: flex;
gap: 30px;
margin-top: 30px;
}
.test-3 {
background-color: orange;
width: 100%;
}
.test-4 {
background-color: gray;
width: 150px;
}
.test-1,
.test-2,
.test-3,
.test-4 {
height: 60px;
}
<h1>Grid</h1>
<div id="main-1">
<div class="test-1"></div>
<div class="test-2"></div>
<div class="test-2"></div>
</div>
<h1 style="margin:30px 0 0 0;padding-top:15px;border-top: 3px solid #000;">Flex</h1>
<p style="margin:0 0 30px 0;">This is the desired layout but with one more extra div</p>
<div>
<div class="test-3"></div>
<div id="main-2">
<div class="test-4"></div>
<div class="test-4"></div>
</div>
</div>

button not aligned with image in div

In the following image , the button (Questions) is lower than the image (white rectangle). They both are inside the same div. Why? The page has a top level css-grid with 3 rows.
.grid-container {
display: grid;
grid-template-rows: [nav-row-start]auto [nav-row-end logo-nav-row-start] auto [logo-nav-row-end content-row-start] auto [content-row-end];
}
.nav-style {
height: 5vh;
/*make nav div take 5% of space of viewport*/
background-color: black;
}
.logo-nav-style {
height: 20vh;
/*make logo-nav div take 20% of space of viewport*/
background-color: gray;
}
.nav-flexbox-container {
display: flex;
flex-direction: row-reverse;
}
.content-style {
height: 75vh;
/*make content div take 75% of space of viewport*/
background-color: white;
}
#nav {
grid-row: nav-row-start/nav-row-end;
margin: 0px;
}
#logo-nav {
grid-row: logo-nav-row-start/logo-nav-row-end;
margin: 0px;
}
#content {
grid-row: body-row-start/body-row-end;
margin: 0px;
}
#profile-pic {
margin: 5px;
}
#mail-icon-pic {
margin: 5px;
}
#stats-icon-pic {
margin: 5px;
}
#logo-image {
/*the max width and max height rule will make the image fit inside the div. If the image is bigger than div, the image will
contract, if the image is smaller than the div, the image will expand*/
max-width: 100%;
max-height: 100%;
}
body {
margin: 0px;
}
<div class="grid-container">
<div id="nav" class="nav-style nav-flexbox-container">
<img id="stats-icon-pic" src="stats_icon.png">
<img id="mail-icon-pic" src="mail_icon.png">
</div>
<div id="logo-nav" class="logo-nav-style">
<img id="logo-image" src="example_logo.png"/>
<button type="button">Questions</button>
<!-- this button is lower than the image-->
</div>
<div id="content" class="content-style">body</div>
</div>
I can't answer the "why" part, but one solution is to add display: flex and align-items: flex-end to .logo-nav-style.
Also, I wouldn't lock .content-style to height: 75vh but use min-height: 75vh instead so the content can expand beyond that.
I'm also confused why you got flex-direction: row-reverse; on your .nav-flexbox-container. Why not just put the elements in the correct order to begin with?
.grid-container {
display: grid;
grid-template-rows: [nav-row-start]auto [nav-row-end logo-nav-row-start] auto [logo-nav-row-end content-row-start] auto [content-row-end];
}
.nav-style {
height: 5vh;
/*make nav div take 5% of space of viewport*/
background-color: black;
}
.logo-nav-style {
height: 20vh;
/*make logo-nav div take 20% of space of viewport*/
background-color: gray;
/* Rickard's addition */
display: flex;
align-items: flex-end;
}
.nav-flexbox-container {
display: flex;
flex-direction: row-reverse;
}
.content-style {
min-height: 75vh;
/*make content div take 75% of space of viewport*/
background-color: white;
}
#nav {
grid-row: nav-row-start/nav-row-end;
margin: 0px;
}
#logo-nav {
grid-row: logo-nav-row-start/logo-nav-row-end;
margin: 0px;
}
#content {
grid-row: body-row-start/body-row-end;
margin: 0px;
}
#profile-pic {
margin: 5px;
}
#mail-icon-pic {
margin: 5px;
}
#stats-icon-pic {
margin: 5px;
}
#logo-image {
/*the max width and max height rule will make the image fit inside the div. If the image is bigger than div, the image will
contract, if the image is smaller than the div, the image will expand*/
max-width: 100%;
max-height: 100%;
}
body {
margin: 0px;
}
<div class="grid-container">
<div id="nav" class="nav-style nav-flexbox-container">
<img id="stats-icon-pic" src="stats_icon.png">
<img id="mail-icon-pic" src="mail_icon.png">
</div>
<div id="logo-nav" class="logo-nav-style">
<img id="logo-image" src="example_logo.png"/>
<button type="button">Questions</button>
<!-- this button is lower than the image-->
</div>
<div id="content" class="content-style">body</div>
</div>

How to fit 2 elements to page height?

I'm developing an app with the interface that is supposed to fit the page (only some internal elements may have scrolling). The basic layout consists of a header and the main section:
<div class="page">
<Navigation/> <!-- a Vue component -->
<main class="page__main">
...
</main>
</div>
currently, CSS has hardcoded height of the header (Navigation):
.page {
height: 100vh;
}
.page__main {
height: calc(100vh - 80px); /* 80px is the height of the header */
}
I'd like to get rid of this hardcoded bit but make sure .page__main's height gets no larger than 100vh - height of Navigation. Is there a way to do this without JS? I suspect that there are some options that can be used with
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
but just using that with
.page__main {
flex-shrink: 1;
}
doesn't work: .page__main has children which use height in percents and once I set flex-shrink: 1; instead of height: calc(100vh - 80px); those grow and the interface is broken.
To illustrate the problem better, here's the current state:
body { padding: 0; margin: 0; }
.page {
height: 100vh;
background: blue;
}
.page__navigation {
height: 80px;
background: gray;
}
.page__main {
height: calc(100vh - 80px);
}
.part1 {
height: 50%;
background: #eeeeee;
overflow-y: scroll;
}
.part2 {
height: 50%;
background: #cccccc;
}
<div class="page">
<div class="page__navigation">nav stuff</div>
<main class="page__main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</main>
</div>
and here's what happen when I try to "set height" via flex:
body { padding: 0; margin: 0; }
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: blue;
}
.page__navigation {
height: 80px;
background: gray;
}
.page__main {
flex-shrink: 1;
}
.part1 {
height: 50%;
background: #eeeeee;
overflow-y: scroll;
}
.part2 {
height: 50%;
background: #cccccc;
}
<div class="page">
<div class="page__navigation">nav stuff</div>
<main class="page__main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</main>
</div>
You can consider a nested flexbox container and don't forget the use of min-height:0; to allow the elements to shrink.
body { padding: 0; margin: 0; }
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: blue;
}
.page__navigation {
height: 80px;
background: gray;
}
.page__main {
flex-grow: 1; /* Fill the remaining space*/
display:flex; /* Nested Container*/
flex-direction:column;
min-height:0; /* Allow the element to shrink */
}
.part1 {
flex-basis: 50%;
background: #eeeeee;
overflow-y: scroll; /* Allow the element to shrink */
}
.part2 {
flex-basis: 50%;
min-height:0; /* Allow the element to shrink */
background: #cccccc;
}
<div class="page">
<div class="page__navigation">nav stuff</div>
<main class="page__main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</main>
</div>
Use flex-grow. Keep everything as the second one (flex one) and change:
Edit
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: blue;
}
.page__main {
height: 100%;
min-height: 0;
flex: 1 1 auto;
}
Three value flex means flex: flex-grow | flex-shrink | flex-basis.
Flex-grow tells our element whether or not it can take up additional space.
Flex-shrink works very similarly to flex-grow, only instead of dealing with extra space, it deals with space not needed by an elements content.
Flex basis is best used when in conjunction with either flex-shrink or flex-grow.
You can check this article to understand better.
I would suggest css-grid approach : -
.page {
background: gray;
display: grid;
grid-template-rows: 100px auto;
height: 100vh;
color: white;
}
.nav {
grid-row: 1/2;
background: brown;
}
.main {
grid-row: 2/3;
background: green;
display: grid;
grid-template-rows: 30% 70%;
}
.part1 {
overflow: auto
}
.part2 {
background: blue
}
<div class="page">
<div class="nav">Nav</div>
<div class="main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</div>
</div>
</div>

CSS Flex Layout: 2 columns out of non-hierarchal elements

I want to display the "right" and "left" elements in 2 columns. The right element should stretch vertically to the full height of the parent. Standard solutions use an extra container for each column. However, in my situation, the columns have no semantic meaning, they are just for display. Further, since my project will have many instances of this structure, adding container elements would introduce a lot of mess.
<div class='container'>
<div class='right'>
<div class='left'>
<div class='left'>
<div class='left'>
<div class='left'>
</div>
The under-appreciated "display:table-cell" almost works, but has some limitations, so that option is out. CSS "display:flex" is the only other potential solution that I can think of. I cannot find a working example, and my attempts have failed, so I hope that you can help me out. Thanks in advanced, -T
display:flex is awesome, but browser support could be an issue. Flex guide.
What's wrong with something like the below?
Fiddle Link!
HTML
<div class="left">
</div><!--
--><div class="right">
</div>
CSS
*, *:before, *:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
width: 100%;
max-width: 500px;
min-width: 200px;
margin: 0 auto;
}
div {
display: inline-block;
height: 100%;
}
.left {
background: #F00;
width: 50%;
}
.right {
background: #000;
width: 50%;
}
Within a flexible container, its children can be stacked vertically or horizontally (not both) via flex-direction. This is why if you want to use flexbox the .left divs should be wrapped in a containing parent. The .container children are stacked horizontally and the .left children are stacked vertically.
Here's fiddle: http://jsfiddle.net/7aK9f/1/.
Here's HTML:
<div class = "container">
<div class= "right">right</div>
<div class = "left">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
CSS:
* {
margin: 0;
padding: 0;
border: 0;
}
html, body {
height: 100%;
}
.container {
height: 100%;
display: -webkit-flex;
display: flex;
-webkit-flex-direction: row;
flex-direction: row;
}
.container > .right {
order: 2;
background-color: #ccc;
-webkit-flex: 3 0 0;
flex: 3 0 0;
}
.container > .left {
order: 1;
background-color: #eee;
-webkit-flex: 7 0 0;
flex: 7 0 0;
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
}
.container > .left > * {
-webkit-flex: 1 0 0;
flex: 1 0 0;
}
.container > .left > div + div {
box-shadow: inset 0 1px 0 0px #000;
}

Resources