{"id":994,"date":"2015-06-01T21:32:17","date_gmt":"2015-06-01T19:32:17","guid":{"rendered":"http:\/\/blogs.igalia.com\/jfernandez\/?p=994"},"modified":"2015-06-02T10:44:49","modified_gmt":"2015-06-02T08:44:49","slug":"distributing-tracks-along-grid-layout-container","status":"publish","type":"post","link":"https:\/\/blogs.igalia.com\/jfernandez\/2015\/06\/01\/distributing-tracks-along-grid-layout-container\/","title":{"rendered":"Distributing tracks along Grid Layout container"},"content":{"rendered":"<p>In my <a href=\"http:\/\/blogs.igalia.com\/jfernandez\/2015\/03\/09\/content-distribution-in-css-grid-layout\/\" target=\"_blank\">last post<\/a> I introduced the concept of Content Distribution alignment and how it affects <a href=\"http:\/\/www.w3.org\/TR\/css-grid-1\/\" target=\"_blank\">Grid Layout<\/a> implementation. At that time, it was possible to use all the &lt;content-position&gt; values to select grid tracks position inside a grid container, moving them across the available space. However, it wasn&#8217;t until recently that users can distribute grid tracks along such available space, literally <strong>adding gaps<\/strong> in between or even <strong>stretching<\/strong> them.<\/p>\n<p>In this post I&#8217;ll describe how each &lt;content-distribution&gt; value affect tracks in a Grid Layout, their position and size, using different grid structures (eg. number of tracks, span).<\/p>\n<p>Let&#8217;s start analyzing the new Content Distribution alignment syntax defined in the <a href=\"http:\/\/dev.w3.org\/csswg\/css-align\" target=\"_blank\">CSS Box Alignment<\/a> specification:<\/p>\n<blockquote><p>auto | &lt;<a href=\"http:\/\/dev.w3.org\/csswg\/css-align\/#typedef-baseline-position\" target=\"_blank\">baseline-position<\/a>&gt; | &lt;<a href=\"http:\/\/dev.w3.org\/csswg\/css-align\/#typedef-content-distribution\" target=\"_blank\">content-distribution<\/a>&gt; || [ &lt;<a href=\"http:\/\/dev.w3.org\/csswg\/css-align\/#typedef-overflow-position\" target=\"_blank\">overflow-position<\/a>&gt;? &amp;&amp; &lt;<a href=\"http:\/\/dev.w3.org\/csswg\/css-align\/#typedef-content-position\" target=\"_blank\">content-position<\/a>&gt; ]<\/p><\/blockquote>\n<p>In case of a &lt;content-distribution&gt; value can&#8217;t be applied, its associated fallback &lt;content-distribution&gt; value should be used instead. However, this CSS syntax allow users to specify a preferred fallback value:<\/p>\n<blockquote><p>If both a &lt;content-distribution&gt; and &lt;content-position&gt; are given, the &lt;content-position&gt; provides an explicit fallback alignment.<\/p><\/blockquote>\n<p>Before going into each value, I think it&#8217;s a good idea to refresh the concepts of <a href=\"http:\/\/dev.w3.org\/csswg\/css-align\/#alignment-container\" target=\"_blank\">alignment container<\/a> and <a href=\"http:\/\/dev.w3.org\/csswg\/css-align\/#alignment-subject\" target=\"_blank\">alignment subject<\/a> and how they apply in the context of Grid Layout:<\/p>\n<blockquote><p>The alignment container is the grid container\u2019s content box. The alignment subjects are the grid tracks.<\/p><\/blockquote>\n<p>The different &lt;content-distribution&gt; values that can be used for align-content and justify-content CSS properties are defined as follows:<\/p>\n<ul>\n<li><strong><a href=\"http:\/\/dev.w3.org\/csswg\/css-align\/#valdef-content-distribution-space-between\">space-between<\/a> &#8211; <\/strong>The alignment subjects are evenly distributed in the alignment container. Default fallback: <strong>start<\/strong>.<\/li>\n<li><strong><a href=\"http:\/\/dev.w3.org\/csswg\/css-align\/#valdef-content-distribution-space-around\">space-around<\/a> &#8211; <\/strong>The alignment subjects are evenly distributed in the alignment container, with a half-size space on either end. Default fallback: <strong>center<\/strong>.<\/li>\n<li><strong><a href=\"http:\/\/dev.w3.org\/csswg\/css-align\/#valdef-content-distribution-space-evenly\">space-evenly<\/a> &#8211; <\/strong>The alignment subjects are evenly distributed in the alignment container, with a full-size space on either end. Default fallback: <strong>center<\/strong>.<\/li>\n<li><strong><a href=\"http:\/\/dev.w3.org\/csswg\/css-align\/#valdef-content-distribution-stretch\">stretch<\/a> &#8211; <\/strong>Any auto-sized alignment subjects have their size increased equally (not proportionally) so that the combined size exactly fills the alignment container. Default fallback: <strong>start<\/strong>.<\/li>\n<\/ul>\n<p>Picture below describes how these values would behave depending on the number of grid tracks; for simplicity I only use justify-content property, so tracks are distributed along the inline (row) axis. In next examples we will see how both properties work together using more complex grid definitions.<\/p>\n<figure id=\"attachment_1004\" aria-describedby=\"caption-attachment-1004\" style=\"width: 589px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/content-distribution.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-1004\" src=\"http:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/content-distribution-1.png\" alt=\"content-distribution-1\" width=\"589\" height=\"381\" srcset=\"https:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/content-distribution-1.png 2608w, https:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/content-distribution-1-300x194.png 300w, https:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/content-distribution-1-1024x664.png 1024w\" sizes=\"auto, (max-width: 589px) 100vw, 589px\" \/><\/a><figcaption id=\"caption-attachment-1004\" class=\"wp-caption-text\">Effect of different Content Distribution values on Grid Layout. <strong>Click<\/strong> on the Image to evaluate the behavior when using different number of tracks.<\/figcaption><\/figure>\n<p>Previous examples were defined with grid items filling <a href=\"http:\/\/www.w3.org\/TR\/css-grid-1\/#grid-area\" target=\"_blank\">grid areas<\/a> of just 1&#215;1 tracks, which makes distribution pretty simple and easier to predict. But thanks to the flexibility of Grid Layout syntax we can define irregular grids, for instance, using the grid-template-areas property like in the next example.<\/p>\n<figure id=\"attachment_1045\" aria-describedby=\"caption-attachment-1045\" style=\"width: 579px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/align-content-and-span-4.png\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-1045\" src=\"http:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/align-content-and-span-4.png\" alt=\"align-content-and span-4\" width=\"579\" height=\"439\" srcset=\"https:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/align-content-and-span-4.png 986w, https:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/align-content-and-span-4-300x228.png 300w\" sizes=\"auto, (max-width: 579px) 100vw, 579px\" \/><\/a><figcaption id=\"caption-attachment-1045\" class=\"wp-caption-text\">Basic example of how to apply the different values and its effect on irregular grid design.<\/figcaption><\/figure>\n<p>Since Content Distribution alignment considers grid tracks as the alignment subject, distributing tracks along the available space may have the consequence of modifying the dimensions of <a href=\"http:\/\/www.w3.org\/TR\/css-grid-1\/#grid-area-concept\">grid-areas<\/a> defined by more than one track. The following picture shows the result of the code above and provides and excellent example of how powerful is the Content Alignment effect on a Grid Layout.<\/p>\n<p>These use cases can be obtained from Igalia&#8217;s Grid Layout <a href=\"http:\/\/igalia.github.io\/css-grid-layout\/\" target=\"_blank\">examples repository<\/a>, so anybody can play with different grid designs and alignment values combinations. They are also available at our <a href=\"http:\/\/codepen.io\/collection\/JoKLd\/\" target=\"_blank\">codepen repository<\/a>.<\/p>\n<h3>Grid Layout behind the scene<\/h3>\n<p>Now I&#8217;d like to explain a bit what I had to implement in the browser&#8217;s webcore to get these new features done; just some small pieces of source code, the ones I considered better, to get an idea of what implementing new behavior in browsers implies.<\/p>\n<p>As you might already know because of my previous posts, CSS Box Alignment specification was born to <strong>generalize Flexbox&#8217;s alignment<\/strong> behavior so that it can be used for grid and even regular blocks. Several new properties were added, like <em>justify-items<\/em> and <em>justify-self<\/em>, and CSS syntax has changed considerably. Specially noteworthy how Content Distribution alignment properties have changed from their initial Flexbox definition. They now support complex values like <em>&#8216;space-between true&#8217;<\/em>, <em>&#8216;space-around start&#8217;<\/em>, or even <em>&#8216;stretch center safe&#8217;<\/em>. This makes possible to express more info than using the previous simple keyword form, although it requires a new CSS parsing logic in Browsers.<\/p>\n<h4>More complex CSS parsing<\/h4>\n<p>Since both <strong>align-content<\/strong> and <strong>justify-content<\/strong> properties accept multiple optional keywords I needed to re-implement completely their parsing logic. I&#8217;m happy to announce that it recently landed WebKit&#8217;s trunk too, so now both web engines support the new CSS syntax.<\/p>\n<p>Due to the complex values defined for theses CSS properties, a new CSSValue derived class was defined to hold all the Content Alignment data, named as <a href=\"http:\/\/src.chromium.org\/viewvc\/blink\/trunk\/Source\/core\/css\/CSSContentDistributionValue.h?pathrev=184660\" target=\"_blank\"><b>CSSContentDistributionValue<\/b><\/a>. This data is then converted to something meaningful for the style logic using the StyleBuilderConverter class. This is the preferred method in both WebKit and Blink engines, which it just needs to be declared in the CSSPropertyNames.in and CSSProperties.in template files, respectively.<\/p>\n<blockquote><p>\nalign-content initial=initialContentAlignment, converter=convertContentAlignmentData<br \/>\njustify-content initial=initialContentAlignment, converter=convertContentAlignmentData\n<\/p><\/blockquote>\n<p>The StyleBuildConverter logic is pretty simple thanks to these 2 new data structures, as it can be appreciated in the following excerpt of source code:<\/p>\n<pre lang=\"C\">StyleContentAlignmentData StyleBuilderConverter::convertContentAlignmentData(StyleResolverState&amp;, CSSValue* value)\r\n{\r\n    StyleContentAlignmentData alignmentData = ComputedStyle::initialContentAlignment();\r\n    CSSContentDistributionValue* contentValue = toCSSContentDistributionValue(value);\r\n    if (contentValue->distribution()->getValueID() != CSSValueInvalid)\r\n        alignmentData.setDistribution(*contentValue->;distribution());\r\n    if (contentValue->position()->getValueID() != CSSValueInvalid)\r\n        alignmentData.setPosition(*contentValue->;position());\r\n    if (contentValue->overflow()->getValueID() != CSSValueInvalid)\r\n        alignmentData.setOverflow(*contentValue->overflow());\r\n    return alignmentData;\r\n}\r\n<\/pre>\n<p>The <a href=\"http:\/\/src.chromium.org\/viewvc\/blink\/trunk\/Source\/core\/style\/StyleContentAlignmentData.h?pathrev=194466\" target=\"_blank\"><b>StyleContentAlignmentData<\/b><\/a> class was defined to simplify how we manage these complex values, so that we can handle properties as they had an atomic value. This approach allows a more efficient and robust way of detecting and managing style changes in these properties.<\/p>\n<h4>New Layout operations<\/h4>\n<p>Once this new CSS syntax is correctly parsed and a <strong>LayoutStyle<\/strong> instance generated according to user defined CSS style rules, I needed to modify Flexbox&#8217;s layout code for adapting it to the new data structures, ensuring browser backward compatibility and passing all the Layout and Unit tests. I implemented from scratch this logic for Grid Layout so I had the opportunity to introduce several performance optimizations to avoid unnecessary layouts and repaints. This area is pretty interesting and I&#8217;ll talk about it soon in a new post.<\/p>\n<p>One interesting aspect of Content Distribution alignment is that it might take part in the track sizing algorithm. As it was explained in my previous post about Self Alignment, <em>stretch<\/em> value increases alignment subject&#8217;s size to fill its alignment container&#8217;s available space. This is also the case of Content Alignment, but considering tracks as alignment subject. However, there is another case not so obvious where &lt;content-distribution&gt; values may influence in track sizing resolution, or perhaps better said, grid area sizing.<\/p>\n<p>Let&#8217;s consider this example of grid where there are certain areas using more than one track:<\/p>\n<pre lang=\"css\">\r\ngrid-template-areas: \"a a b\"\r\n                     \"c d b\"\r\ngrid-auto-columns: 20px;\r\ngrid-auto-rows: 40px;\r\nwidth: 150px;\r\nheight: 300px;\r\n<\/pre>\n<p>The example above defines a grid with 3 column tracks of 20px and 2 row tracks of 40px, which would be laid out as it&#8217;s shown in the following diagram:<\/p>\n<figure id=\"attachment_1070\" aria-describedby=\"caption-attachment-1070\" style=\"width: 453px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/content-distrbution-spans.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-1070\" src=\"http:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/content-distribution-spans.png\" alt=\"content-distribution-spans\" width=\"453\" height=\"523\" srcset=\"https:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/content-distribution-spans.png 761w, https:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/content-distribution-spans-260x300.png 260w\" sizes=\"auto, (max-width: 453px) 100vw, 453px\" \/><\/a><figcaption id=\"caption-attachment-1070\" class=\"wp-caption-text\">Grid Layout with areas filing more than one track. <b>Click<\/b> on the picture to evaluate the effect of each value on the grid area size.<\/figcaption><\/figure>\n<p>This fact has interesting implementation implications due to the fact that in certain cases, in order to determine grid item&#8217;s logical height we need its logical width to be resolved first. Track sizing algorithm uses children grid area size to determine grid cell&#8217;s logical height, hence given that alignment logic needs track sizes have been already resolved, it may imply a re-layout of the grid items which size could be affected by the used content-distribution value. The following source code shows how I handle this scenario:<\/p>\n<pre lang=\"C\">\r\nLayoutUnit LayoutGrid::gridAreaBreadthForChild(const LayoutBox& child, GridTrackSizingDirection direction, const Vector& tracks) const\r\n{\r\n    const GridCoordinate& coordinate = cachedGridCoordinate(child);\r\n    const GridSpan& span = (direction == ForColumns) ? coordinate.columns : coordinate.rows;\r\n    const Vector& trackPositions = (direction == ForColumns) ? m_columnPositions : m_rowPositions;\r\n    if (span.resolvedFinalPosition.toInt() < trackPositions.size()) {\r\n        LayoutUnit startOftrack = trackPositions[span.resolvedInitialPosition.toInt()];\r\n        LayoutUnit endOfTrack = trackPositions[span.resolvedFinalPosition.toInt()];\r\n        return endOfTrack - startOftrack + tracks[span.resolvedFinalPosition.toInt()].baseSize();\r\n    }\r\n    LayoutUnit gridAreaBreadth = 0;\r\n    for (GridSpan::iterator trackPosition = span.begin(); trackPosition != span.end(); ++trackPosition)\r\n        gridAreaBreadth += tracks[trackPosition.toInt()].baseSize();\r\n\r\n    return gridAreaBreadth;\r\n<\/pre>\n<p>The code above will return different results, in the cases mentioned before, depending on whether it's run during track sizing alignment or after applying the alignment logic. This will likely make needed a new layout of the whole grid, or at least, the affected grid items, which it likely has a negative impact on performance.<\/p>\n<h3>Current status and next steps<\/h3>\n<p>I'd like to finish this post with a snapshot of current situation and challenges for the next months, as I've been regularly doing in my last posts.<\/p>\n<p>Unlike last reports, this time I've got good news regarding reduction of implementation gaps between the two web engines we are focusing our efforts on, WebKit and Blink. The following table describes current situation:<\/p>\n<p><a href=\"http:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/alignment-status.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter  wp-image-1082\" src=\"http:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/alignment-status.png\" alt=\"alignment-status\" width=\"656\" height=\"385\" srcset=\"https:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/alignment-status.png 715w, https:\/\/blogs.igalia.com\/jfernandez\/files\/2015\/05\/alignment-status-300x176.png 300w\" sizes=\"auto, (max-width: 656px) 100vw, 656px\" \/><\/a><\/p>\n<p>The table above indicates that several milestones were reached since the last report, although there are still some pending issues:<\/p>\n<ul>\n<li>I've completed the implementation in WebKit of the parsing logic for the new Box Alignment properties: align-items and align-self.<\/li>\n<li>As a side effect, I've also upgraded the ones already present because of Flexbox to the latest CSS3 Box Alignment specification.<\/li>\n<li>WebKit has now full support for Default and Self Alignment fro Grid Layout, including also overflow handling<\/li>\n<li>Blink has now full support for Content Distribution alignment, which missed &lt;content-distrbuton&gt; values.<\/li>\n<li>WebKit's Grid Layout implementation still misses support for Content Distribution alignment.<\/li>\n<li>Baseline Alignment is still missing in both web engines<\/li>\n<\/ul>\n<p>In addition to the above mentioned pending issues, our <strong>roadmap<\/strong> include the following tasks as part of my <strong>todo<\/strong> list for the next months:<\/p>\n<ul>\n<li>Even though there s support for different writing-modes and flow directions, there are still some issues with <strong>orthogonal flows<\/strong>. I've got already some promising patches but they still have to be reviewed by Blink and WebKit engineers.<\/li>\n<li>Optimizations of style and repaint invalidations triggered by changes on the alignment properties. As commented before, this is a very interesting topic involving, which I'll elaborate further in next posts.<\/li>\n<li>Performance analysis of relevant Grid Layout use cases, which hopefully will lead to optimizations proposals.<\/li>\n<\/ul>\n<p>All this work and many other contributions to Grid Layout for WebKit and Blink web engines are the result of the collaboration between <a href=\"http:\/\/www.bloomberg.com\/company\/\" target=\"_blank\">Bloomberg<\/a> and <a href=\"http:\/\/www.igalia.com\" target=\"_blank\">Igalia<\/a> to implement this W3C specification.<\/p>\n<p><img decoding=\"async\" class=\"size-full wp-image-1489\" src=\"http:\/\/blogs.igalia.com\/mrego\/files\/2014\/03\/igalia-bloomberg.png\" alt=\"Igalia &amp; Bloomberg logos\" width=\"400\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my last post I introduced the concept of Content Distribution alignment and how it affects Grid Layout implementation. At that time, it was possible to use all the &lt;content-position&gt; values to select grid tracks position inside a grid container, moving them across the available space. However, it wasn&#8217;t until recently that users can distribute &hellip; <a href=\"https:\/\/blogs.igalia.com\/jfernandez\/2015\/06\/01\/distributing-tracks-along-grid-layout-container\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Distributing tracks along Grid Layout container<\/span><\/a><\/p>\n","protected":false},"author":20,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[19,20,12,21],"tags":[],"class_list":["post-994","post","type-post","status-publish","format-standard","hentry","category-blink","category-css-grid-layout","category-webkit","category-webkit-igalia"],"_links":{"self":[{"href":"https:\/\/blogs.igalia.com\/jfernandez\/wp-json\/wp\/v2\/posts\/994","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.igalia.com\/jfernandez\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.igalia.com\/jfernandez\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.igalia.com\/jfernandez\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.igalia.com\/jfernandez\/wp-json\/wp\/v2\/comments?post=994"}],"version-history":[{"count":88,"href":"https:\/\/blogs.igalia.com\/jfernandez\/wp-json\/wp\/v2\/posts\/994\/revisions"}],"predecessor-version":[{"id":1098,"href":"https:\/\/blogs.igalia.com\/jfernandez\/wp-json\/wp\/v2\/posts\/994\/revisions\/1098"}],"wp:attachment":[{"href":"https:\/\/blogs.igalia.com\/jfernandez\/wp-json\/wp\/v2\/media?parent=994"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.igalia.com\/jfernandez\/wp-json\/wp\/v2\/categories?post=994"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.igalia.com\/jfernandez\/wp-json\/wp\/v2\/tags?post=994"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}