Open polarathene opened 4 years ago
So I spent a day yesterday looking into what it would take to implement CSS Grid in Stretch. And I thought I would write up my findings.
Useful Resources:
MVP Implementation Plan:
[ ] Extend the Style and Geometry sections of Stretch to include definitions for CSS Grid styles, while ensuring that the existing Flex implementation continues to work:
fr
unitsgrid-template-columns
/grid-template-rows
/grid-template-areas
grid-auto-rows
/grid-auto-columns
/grid-auto-flow
grid-row-start
/grid-row-end
/grid-column-start
/grid-column-end
row-gap
/column-gap
[ ] Implement resolving the "explicit grid". This is the rows, columns and areas (cells) as defined by grid-template-columns
/grid-template-rows
/grid-template-areas
(Sections 7.1-7.4 of the spec)
[ ] Implement grid placement. Matching Grid Items (child nodes of the grid) to Grid Areas. This may include generating extra rows and columns that form the "implicit grid" if any Grid Items are placed outside of the bounds of the "explicit grid". (note: the "implicit grid" is the whole grid, not just the extra bit) (Sections 7.5-8.5 of the spec)
[ ] Implement the Grid Sizing Algorithm to determine the size of each Grid Area. This mostly consists of the Track Sizing Algorithm, iterated a few times. A Grid Track is a row or column of the grid. (Section 11 of the spec).
[ ] Resolve Grid Item (node) sizes, by matching them to the Grid Areas.
Further tasks for full support:
Blocking questions / issues:
min-size
(e.g. text node that wraps at all opportunities) and max-size
(e.g. a text node that doesn't wrap at all). Possibly these would need to be added to nodes as additional "measure functions"? Or possibly they could both be assumed to be equal to the one measure functions at first? Possibly min can be obtained by passing the MeasureFunc width: 0, height: 0
, and max can be obtained by passing the MeasureFunc width: undefined, height: undefined
? https://www.w3.org/TR/css-sizing-3/#intrinsic-contributioncompute_internal
function. I feel like this may be a prerequisite to getting Grid and Flex to play nicely with each other.@emilsjolander Does this look about right to you? Do you have any comments, corrections, or suggestions?
@nicoburns this looks like a very solid plan. The only thing I can see is missing is testing :) One of the first steps should be extending the current test harnesses to support Grid and then also adding a significant number of test cases.
Really looking forward to seeing how this progresses! Please open up a PR early in the process just so we can help comment and see what is going on :)
Very curious / excited to see where this goes!
Awesome!
Would this type of Grid layout be useful for a test case? It uses fixed columns counts(repeat()
+ 1fr
) until 1200px wide, then minmax()
with repeat()
to auto-fit as many columns of a min/max limit.
Rows are also a bit dynamic, and previously was a bit more complicated to keep the cells properly packed without unwanted spaces at certain viewport widths and rows. fit-content()
resolved all that along with pre-processing the images to specific aspect ratios rather than relying on grid and CSS alone. The older CSS and images for that are available in git history if you'd want to use those for additional testing.
Then dense row packing is used since without that, empty spaces would not be filled. I think it's a good example of CSS grid.
Current CSS for grid is like this:
background-color: #191723;
display: grid;
grid-gap: 5px;
grid-auto-flow: row dense;
grid-auto-rows: min-content;
grid-template-columns: var(--column-count, 1fr);
@media (min-width: 320px) {
--column-count: 1fr 1fr;
}
@media (min-width: 640px) {
--column-count: repeat(3, 1fr);
/* Beneficial from this breakpoint forward */
grid-auto-rows: fit-content(350px);
}
@media (min-width: 960px) {
--column-count: repeat(4, 1fr);
}
/* Limit the width of cells from this size onwards */
@media (min-width: 1200px) {
--column-count: repeat(auto-fit, minmax(280px, 1fr));
}
/* These breakpoints have some unfilled areas, fill them */
@media (min-width: 640px) and (max-width: 959.98px) {
> div:nth-child(23) {
grid-row: span 2;
}
}
@media (min-width: 1705px) and (max-width: 2274.98px) {
> div:nth-child(20) {
grid-row: span 2;
/* override internal inline style */
img {
object-position: left !important;
}
}
}
/* 2560px is next breakage */
/* Related CSS on Grid item components: */
@media (min-width: 320px) {
${props => props.type === "wide" && "grid-column: span 2;"}
${props => props.type === "tall" && "grid-row: span 2;"}
${props => props.type === "big" && "grid-column: span 2; grid-row: span 2;"}
}
If not on a desktop device, here's some different viewport widths to show off the grid adapting:
Here we've reached fixed column breakpoints, and you can see how the vertical/tall cell in the middle has a more narrow aspect ratio to pack nicely into the grid, despite sharing the same CSS and image dimensions as the other tall images.
Just noticed that I need to push an update to the live version as it's presently using older CSS(some CSS variables to do calc()
scaling at <720px on grid row/col values), which aren't necessary with the fit-content()
rule I had switched to. At <640px, grid-auto-rows
should be auto
or min-content
so that the single row/col grid items produce variable heights for some more interesting packing/layout variation like shown on the right here beside that tall two row cell:
At <320px, every grid item is just 1 col/row spans:
Opening this as a tracking issue.
I understand there is an intent for
stretch
to support CSS Grid in future, so for anyone interested in knowing when/if that happens, they can watch this issue for updates and/or show interest/support via :+1: reaction(to this issue, no +1 type comments thanks!).While slightly biased due to React-Native using
yoga
for layout, there is strong interest in seeing CSS Grid support with little indication from yoga devs that the feature is on the horizon.