I am trying to use an implicit CSS grid to generate a layout for the following basic HTML structure:
<div class='row'>
<textarea></textarea>
<div></div>
</div>
where the .row div is a CSS grid with an auto-flow set to column for automatically placing elements as columns:
.row {
display: grid;
grid-auto-flow: column;
}
I would expect, as with most elements, that the CSS grid would provide equal space to both the textarea and the div elements along the row. But instead, the layout looks like this:
The textarea takes up more space along the row than expected. When you try to resize the textarea, I see the following:
What seems to be happening here is the grid is adding additional space to the right of the textarea equal to the width of the div on the right. What I can't figure out is why this is happening, and why the elements don't initially have an equal width. What am I missing here?
I've created a simple JSFiddle for testing this behavior here.
To make them the same size you need to ask the grid to do that
grid-auto-columns:1fr;
You can stop the user resizing the textarea with resize:none
If you want to get this to work whilst letting the user resize, I couldn't find a css solution
I had an idea but I couldn't get it to work.
The gist was
have a set of [invisible] divs as a first row
have a function that can be called on an element of a grid to see if its offsetWidth is lesser to one of the hidden divs of the same column
if it is, manipulate the css from auto to setting the width explicitly to the textarea's for that column, then with some mix of repeat(x, 1fr) (pre-textarea columns) & repeat(auto-fill, 1fr) (post-textarea columns)
then attach this function to the resize (or mouseup) of the textarea
Alternatively, consider flex.
It will have the opposite problem; it wont force an element to be 1fr (and apply that unwanted padding), but I dont think you can ask it to be 1/<number in row> in size [in css only] either.
why the elements don't initially have an equal width. What am I missing here?
textarea has a width initially defined by cols which has a default value equal to 20
cols
The visible width of the text control, in average character widths. If it is specified, it must be a positive integer. If it is not specified, the default value is 20.
This width play a role in defining the initial width of the textarea. You can set a small value to make sure it behave almost the same as div.
.row {
display: grid;
grid-auto-flow: column;
}
.row > div {
border: 1px dotted;
}
<div class='row'>
<textarea cols=1></textarea>
<div></div>
</div>
You can still notice a small difference since the textarea is not having an initial width exactly equal to 0 and it also has some padding so its column will logically be a little bigger.
To avoid this and to also fix the resize issue better explicitely define the grid like below where you set the initial width of the textarea to be half the width of grid.
I don't know your real use case but I will consider the fact that your grid is full page width (I will also consider the default body margin)
.row {
display: grid;
grid-template-columns:auto 1fr;
}
.row > div {
border: 1px dotted;
}
textarea {
width:calc(50vw - 16px);
box-sizing:border-box;
}
<div class='row'>
<textarea ></textarea>
<div></div>
</div>
Related
I have a parent section div with a max-width of 1760px.
I can put a carousel directly inside a section container and it will take the width of the viewport up to 1760px i have set, works as expected. *carousel will try to fill 100% of space given.
However, the issue is that i want to put the content inside a 2 col grid, inside container, but the first part of the grid has the carousel that takes the max-width of parent section, rather than stopping at width of page. So, rather than take 2fr of the viewport (map takes 1fr), it fills whole of 1760px so the screen overflows.
Style wise, The best example i can find online to show what i mean is Airbnb listing, it has 2 cols, 1 with listing and 1 with map. This is pretty much what i am trying to replicate.
Here is the carousel directly in section (pretty simple and works as explained above). If i put the carousel inside this it doesn't overflow page.
<section>
<div>Carousel</div>
</section>
section{
max-width: 1760px;
padding: 50px 40px;
margin: 0 auto;
}
Once i add it inside a grid it ignores the viewport size and simply fills max-width of section (1760px) and overflows viewport width.
<section>
<div class="grid">
<div>Carousel</div>
<div>Map</div>
</div>
</section>
.grid{
display: grid;
grid-template-columns: 2fr 1fr;
grid-gap: 20px;
}
It actually works using grid-template-columns: 60% 40%; instead of 2fr 1fr, and removing margin: 0 auto. But this means i cannot use gap (which is fine).
To summerize, how can i use fr sizing and make sure it takes notice of viewport size, and not just take up the max-width value by default.
I went through your pen and made some changes and it gave the result as you wanted it to be, no overflowing of the image.
If you do following changes, it will work for you too:
These are not mandatory, if you wish you can do the changes or else you can keep as it is.
Remove the max-width: 1760px from section style.
Add max-width: 1760px to the grid element, since you are providing the max-width to the grid, the parent section will also have this max-width, since grid is the child element.
Now make sure you are applying the width: 100% to the images (This is mandatory). Like this:
.listing > img {
width: 100%;
}
OR, if you have nested elements inside .listing element and img tag is not the immediate child of the .listing element, then you can go with this way:
.listing img {
width: 100%;
}
So every img tag which is direct or indirect descendent of .listing element will have width 100%
Here's the working piece of example:
https://codepen.io/prathameshkoshti/pen/KKMYoWY?editors=0100
I have the following simple layout (with the exception that the textarea becomes a Code Mirror at runtime):
<div class="columns">
<div class="column is-paddingless" style="background: indigo;">
<textarea id="code-editor"></textarea>
</div>
<div class="column">
</div>
</div>
The problem is - the first column does not fill the vertical space of the page (below the tabs) - rather it just wraps the height of the textarea. For instance:
Is there a way to make the column fill the page?
Flexbox should work for you! For your reference I love this guide: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
Setting up your .columns like this should do the trick:
.columns {
display: flex;
flex-direction: row; // this is default
align-items: stretch; // this will stretch the children vertically
}
Unsure how you have .column styled (ie height: 100%) but let me know if this does NOT work and I can troubleshoot further.
Give a class or id or just write inline style and do
min-height : XXvh;
Where xx is how VH you need.
According to MOzila devaloper
vh
Equal to 1% of the height of the viewport's initial containing block.
I am using the new css grid like this:
#site {
display: grid;
grid-template-columns: 10% 1fr 1fr 1fr 10%;
grid-template-rows: 100px auto;
grid-template-areas:
". header header header ."
". content content sidebar ."
}
So I have tow rows and 5 columns but only 3 columns with content. I'm using the dot in the template areas to define a white space.
This results in having a 3 column layout with white space on the left and right side.
If I place an element in a grid area that has a background color the white space left and right stays white (logically).
What I want is a full width background (color) but I'm not really sure how to realise this. One option I have in mind is to have a second grid in the background that has the same columns and rows but not the white spaces and then I can fill it up with color but I think this is not best practice.
Best I have found is put the grid inside a container for a certain width to center the content. And have items you need to extend the background give a huge left/right padding, and same margin negative.
Just be sure to give body an overflow-x: hidden;
<div class="container">
<div id="site">
<div class="header"></div>
<div class="content"></div>
<div class="footer"></div>
</div>
</div>
And the CSS:
.container{
width:1000px;
margin: 0 auto; //
}
#site {
display: grid;
grid-template-columns: 10% 1fr 1fr 1fr 10%;
grid-template-rows: 100px auto;
grid-template-areas:
". header header header ."
". content content sidebar ."
}
.header{
background: red;
padding: 0 3000px;
margin: 0 -3000px;
}
body{
overflow-x: hidden;
}
I see 3 options here
You can set one or multiple backgrounds using CSS background color. Also this way you can set gradients and solid color can be imitated using gradients.
Create grid item with background and manually set grid-row and grid-column with values that you need. This items should have negative z-index to be overlapped by other grid items (z-index is working even for statically positioned for grid items, the same is true about flex items).
Absolutely positioned elements of grid container.
It sounds like what you're looking to do may be best addressed by the upcoming Subgrid feature, arriving in Level 2 of CSS Grid: this will allow outer elements and their children to both be laid out using the same grid.
As of today (Aug 8th, 2019) Subgrid has shipped in Firefox nightly, so will hopefully land in a real release soon (tracked here). Unfortunately, there hasn't been much movement yet from the Chrome team (please star the issue in the Chrome bug tracker to show your support)
In lieu of Subgrid arriving, what I've done is either define the same grid lines inside the container element, or, for the specific case of a full-width background, define a padding on the wrapper element that is equal in size to the width of the "empty" gutters on either side of the page. This is easiest/most reliable if you use vw units, and is fairly straightforward with the use of a variable in SASS or LESS
I simply can't figure this out: I have a div that is centered on screen with a width of 60%. Inside this div I have 3 more divs that float left with the width of 33% and have a gray bg color. The divs are filled with text and one image per div. Each div should now take 1/3 space inside the "maindiv". This works fine but as soon as I give my 3 "contentdivs" a padding so the text gets seperated a bit the third div wanders below the others. I also want a margin around my 3 divs so there is a gap between all the divs. But this only works if I give the divs a width of like 31%. As soon as I shrink my browser though, the third one pops up below the others again.
How it looks now:
How it looks with a width of 33.33%
How can fix this? I mean I set the divs to a relative width by setting the size in %. So the divs should just shrink as soon as I shrink my browser window. I tried to surround all the divs by other divs and messed around with margins and paddings but it just won't work.
Most likely it’s box model’s fault. Paddings, margins and borders can be added together in different ways. Add box-sizing:border-box to the container and its elements. Most certainly this brings about what you intended to do, and width:33.3333% wil work out as expected.
Adding margin still breaks the item? There’s another great thing called calc(). Assumed you have a margin of 8px, that’s just a few pixels too much. With calc(), you can subtract the additional margin like this:
.item{ width:calc(33.3333vw - 8px); }
Note that there must be whitespace around the minus. Try it and include your margin.
Apply box-sizing: border-box to all related elements (or the entire document, as Bootstrap does). http://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing
Then, rather than margin, use padding for the outer spacing. This eliminates the need to do mental math altogether.
div {
box-sizing: border-box;
}
.one-third, .inner, .full-width {
padding: 8px;
}
.one-third {
float: left;
width: 33.333%;
}
.inner {
background-color: pink;
}
<div class="full-width">
<div class="inner">Full-width div</div>
</div>
<div class="one-third">
<div class="inner">Content</div>
</div>
<div class="one-third">
<div class="inner">Content</div>
</div>
<div class="one-third">
<div class="inner">Content</div>
</div>
Fiddle demo
Your best bet would be to get the three columns and margins to equal 100%. This is fairly easy if you know you are only having three columns:
.item {
width:32%;
margin-left:2%;
}
.item:first-child {
margin-left:0;
}
As long as there is only three it will always add up to 100% as you are overriding the first .item. If you don't override the first item then you will have a space before your columns and the last column won't fit. Mixing pixels and percentages will give you issues in a grid (unless they're paddings and you are using box-sizing). Margin is not included in the box-sizing as it is not part of the main box model.
When using css flexbox the three main browsers appear to behave entirely differently in certain areas.
In this case I am trying to create a grid of images:
<div class="container">
<div class="photo"></div>
<div class="photo"></div>
<div class="photo"></div>
<div class="photo"></div>
<div class="photo"></div>
<div class="photo"></div>
</div>
.container {
display:inline-flex;
flex-flow : column wrap;
align-content : flex-start;
height : 100%;
}
In this example I need a container, itself containing several div elements set up to flow from top to bottom and wrapping when they reach the bottom. Ultimately providing me with columns of photos.
However I need the container to expand horizontally to accommodate the wrapped elements:
Here is a quick jsFiddle to demonstrate.
The behaviour is as follows:
IE 11 - Correct, the container stretches horizontally to wrap each column of wrapped elements
Firefox - The container only wraps the first column of elements, with the rest overflow out.
Chrome - The container always stretches to fill the width of its parent, whatever that may be.
In this instance I would like to achieve the behaviour of IE11 in the other two browsers. Therefore my question is, how can I make a flexbox container expand horizontally to match its column wrap contents.
Thanks in advance.
It's curious that most browsers haven't implemented column flex containers correctly, but the support for writing modes is reasonably good.
Therefore, you can use a row flex container with a vertical writing mode. This will swap the block direction with the inline direction, and thus the flex items will flow vertically. Then you only need to restore the horizontal writing mode inside the flex items.
.container {
display: inline-flex;
writing-mode: vertical-lr;
flex-wrap: wrap;
align-content: flex-start;
height: 350px;
background: blue;
}
.photo {
writing-mode: horizontal-tb;
width: 150px;
height: 100px;
background: red;
margin: 2px;
}
<div class="container">
<div class="photo">1</div>
<div class="photo">2</div>
<div class="photo">3</div>
<div class="photo">4</div>
<div class="photo">5</div>
<div class="photo">6</div>
<div class="photo">7</div>
<div class="photo">8</div>
<div class="photo">9</div>
</div>
This approach may have its own bugs in edge cases, especially if you mix advanced layout techniques like floats and nested flexboxs. But for most cases it seems to work properly.
The spec says that what you're doing should work, but it's implemented incorrectly in every major browser besides Internet Explorer / Edge, making multi-line inline-flex column layouts useless at present for most developers. Here's a Chromium bug report providing an example that is effectively identical to yours, and noting that it renders incorrectly in Chrome, Safari, and Firefox.
The argument from spec is more complicated than I'm able to understand, but the key point is that Flexible Box Layout Module Level 1 spec defines the intrinsic cross-size of a flex container (that is, the intrinsic height of a flex-direction: row flex container or the intrinsic width of a flex-direction: column flex container) in the section Flex Container Intrinsic Cross Size. There, it is stated:
For a multi-line flex container, the min-content/max-content cross size is the sum of the flex line cross sizes
That is, the intrinsic width of a flex-direction: column flex container should be the sum of the widths of its columns, as you'd expect. (There is more complexity than this, and I don't understand it all, but I believe the above to be broadly true.) However, Chrome, Firefox, and Safari all calculate this width incorrectly; setting width: min-content or width: max-content on a column wrap flex box in Chrome, you can clearly see that the width is set to the width of the widest single element.
A silly Chrome-specific workaround exists, but is probably best avoided. Until the bug is fixed, this part of the Flexbox model simply doesn't work as designed and there's no clean solution available.
It seems this issue cannot be solved only with CSS, so I propose you a JQuery solution
container width = position of the last child - position of the container + width of the last child (including margin)
Code :
$(document).ready(function() {
$('.container').each(function( index ) {
var lastChild = $(this).children().last();
var newWidth = lastChild.position().left - $(this).position().left + lastChild.outerWidth(true);
$(this).width(newWidth);
})
});
Demo :
http://jsfiddle.net/qzea320L/
You have a column layout distribution with a fixed height container.
When you set the flex-direction to column you define the Vertical axis as the main axis.
In flexbox that means it will fill up the available height and then create a new column.
In this JSBIN I use javascript to change the container's height and, because of that, you will see the child items move.
PS: you shouldn't rely on IE behavior since their flex support is recent.
Another possible approach:
.container {
column-count: 2; /*or whatever */
}
.container > div {
display: inline-block;
}
https://developer.mozilla.org/en-US/docs/Web/CSS/column-count
You may also need to adjust margin-top of .container > div:first-child if they don't align to the top.