I am trying to make a simple sidebar layout with a flat HTML structure, in which the first <aside> element fills in the 1st column completely.
My problem is, that the negative row end value seems to not work for the implicitly created rows for all my elements in the 2nd column.
Expected:
Actual:
Below is a runnable code snippet that illustrates the problem.
article {
display: grid;
grid-template-columns: 200px 1fr;
background: gray;
}
aside {
grid-row: 1/-1;
grid-column: 1/2;
background: pink;
}
section {
grid-column: 2/3;
background: yellow;
}
<article>
<aside>In the left column (top to bottom)</aside>
<section>In the right column</section>
<section>In the right column</section>
<section>In the right column</section>
</article>
You can only use negative integers in an explicit grid.
See the Grid spec here:
7.1. The Explicit
Grid
Numeric indexes in the grid-placement properties count from the edges
of the explicit grid. Positive indexes count from the start side
(starting from 1 for the start-most explicit line), while negative
indexes count from the end side (starting from -1 for the end-most
explicit line).
and here...
8.3. Line-based Placement: the grid-row-start, grid-column-start, grid-row-end, and grid-column-end properties
If a negative integer is given, it instead counts in reverse, starting
from the end edge of the explicit grid.
Making a grid area span an entire column / row, including implicit tracks, when the number of tracks in the grid is unknown, is not possible in CSS Grid Level 1, unless you want to try to hack it.
Related
See this fiddle.
Consider a grid of words in four columns, with each column being the same width. I can get this with grid-template-columns: repeat(auto-fill, minmax(25%, 1fr)); Most of the time, these will be short words. But there could be a long word which overflows its block:
If this were static data, I could have just changed the grid css to grid-template-columns: repeat(auto-fill, minmax(33%, 1fr)); to comfortably fill the space:
How can I make the CSS renderer adjust the number of columns for me, making each the same width, using the width of the widest word block in the set?
I'm surprised that CSS doesn't (as far as I can tell) support this since I think it should be a common use case for wrapping grids. I tinkered until I had a solution with a minimal amount of javascript:
example fiddle with IIFE
First, we need to find out how wide the widest string (or could be any block element) will be when rendered on the client. grid-template-columns: repeat(1, max-content); will do that by arranging the elements in a single column, and all elements get the width of the widest one. After the dimensions are established but before being rendered to the screen, grab any element, compute the number of columns that will fit, then change the CSS for the container to have that many columns + 1fr to make them fill the space:
(function(){
const ul = document.querySelectorAll('ul')[0];
const ee = [...document.querySelectorAll('li')];
const max = ee.map(e=>e.offsetWidth).reduce((a,b)=>Math.max(a, b));
const cols = Math.min(5,Math.floor(ul.offsetWidth/max));
ul.style.gridTemplateColumns = "repeat("+cols+", 1fr)";
})();
This seems to work with no flicker in all evergreen browsers. Angular version I used:
ngAfterViewInit(): void {
const ul: HTMLElement = this.ul.nativeElement;
let cols: number = 0;
const w: number = ul.children[0].clientWidth;
if (w > 0) {
cols = Math.min(5, Math.floor(ul.offsetWidth / w));
}
ul.style.gridTemplateColumns = "repeat(" + cols + ",1fr)";
}
As far as I know this is unsolvable with CSS-only, so, I will provide a Javascript-based solution.
First of all, let's find the longest text:
let longestText = '';
for (let text of texts) {
if (longestText.length < text.length) longestText = text;
}
Then, you can find that item:
let lng = document.querySelectorAll('ul li').filter((item) => item.innerText === longestText)[0].offsetWidth;
Then you can divide the whole width that you have at your disposal with lng, the value you have just calculated and see how many columns you can have.
I am using CSS Grid in my layout...
How do I set different column size on first row and full width on second row?
Is this possible?
Thank you so much!!!
This is not possible, the idea of css grid is to have a "grid", that is all the rows follow the same column configuration.
What you can do however is have an element span several column, and here you have several options:
This one stretches from the first column to the first from the end
div:nth-child(3) {
grid-column: 1 / -1;
}
This one spans 2 columns from the first one:
div:nth-child(3) {
grid-column: 1 / span 2;
}
I have a special css grid layout that is based on completely square grid boxes that are defined like this:
grid-template-columns: repeat(5, minmax(200px, 20vw));
grid-auto-rows: minmax(200px, 20vw);
grid-template-areas:
"branding nav nav . meta"
". title title featured-image ."
". primary primary featured-image ."
". secondary secondary featured-image ."
". footer footer . .";
problem is that I need to have a content area within this grid that is flexible. By default it spans 2 columns and 2 rows. The content area is outlined in red:
I would like the layout to make it possible for the content area to span for example 2 columns and 4 rows for example. Basically 2-n rows based on the content.
Is there any smart way of doing this?
I did something similar for a HomePage, but using JavaScript not just CSS grid:
A card grid ocupying 2 rows only if the contents overflow the container.
static expandIfActive(card){
const content = card.querySelector('.content')
const body = card.querySelector('.card-body')
return body.clientHeight - options.clientHeight - (#margins and paddings) == 0
}
If the content matches the heigth of the container means it's overflowing, so I add the property grid-row: span 2
What does the CSS3 style grid-column-start: 2; do?
Please try to answer from the following:
• Generates grid with 2 columns
• Creates a grid item on second column
• Starts grid item from second column
• Creates a 2×2 grid
It determines a grid item's location within the grid by referring to specific grid lines.
grid-column-start/grid-row-start is the line where the item begins, and grid-column-end/grid-row-end is the line where the item ends.
For Your case suppose following css property
.item-a{
grid-column-start: 2;
grid-column-end: five;
grid-row-start: row1-start
grid-row-end: 3
}
The output will be See this image
Starts grid item from second column
I've added a left and right padding to the header of the QTreeView using this QSS code:
QHeaderView::section{padding:7px 15px}
But the content of the columns is not aligned anymore with the headers.
How can I add a padding of 15px ( like in the header ) to the columns' content?
Edit: For some reasons I use delegates to draw the content of the QTreeView, that's why styling the QTreeView::item doesn't work ( like #svlasov suggested ).
painter.translate(15, 0) seems to fix this issue, but a weird effect appears when I select a row: the selection is not continuous.
Something like this:
QTreeView::item { border: 0px; padding: 0 15px; }
This is rude and crude, but it does what you're asking for in a real simple way for a 3 column QTreeWidget.
// Okay, I want to make sure my columns are wide enough for the contents, but I also
// Don't want them squished together. So use resizeColumnToContents, to make them
// as small as they can be to show the contents, then take those widths and add some
// spacing and then set the columns to the new widths.
m_tree->resizeColumnToContents (0);
m_tree->resizeColumnToContents (1);
int w0 = m_tree->columnWidth (0) + 20;
int w1 = m_tree->columnWidth (1) + 20;
m_tree->setColumnWidth (0, w0);
m_tree->setColumnWidth (1, w1);