-
-
Save FlyingDR/81ce09b9226f8ad0182d08ea764fe02a to your computer and use it in GitHub Desktop.
Customizable CSS grid layouts with support for IE 11
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Excerpt of configuration to display layout definitions | |
@include r-config(desktop, ( | |
media-query: desktop, | |
content: ( | |
layout: ( | |
template: ( | |
regular2: ( | |
columns: 1fr 1fr, | |
rows: auto, | |
), | |
regular4: ( | |
columns: 1fr 1fr, | |
rows: auto auto, | |
), | |
regular6: ( | |
columns: 1fr 1fr, | |
rows: auto auto auto, | |
), | |
regular8: ( | |
columns: 1fr 1fr, | |
rows: auto auto auto auto, | |
), | |
large-1small: ( | |
columns: 2fr 1fr, | |
rows: auto, | |
item-style: ( | |
( | |
type: opinion, | |
style: small, | |
scope: not-first, | |
), | |
), | |
), | |
large-2small: ( | |
columns: 2fr 1fr 1fr, | |
rows: auto, | |
item-style: ( | |
( | |
type: opinion, | |
style: small, | |
scope: not-first, | |
), | |
), | |
), | |
large-4small: ( | |
columns: 2fr 1fr 1fr, | |
rows: auto auto, | |
cells: ( | |
1: 1 1 1 2, | |
), | |
item-style: ( | |
( | |
scope: first, | |
style: large, | |
), | |
( | |
scope: not-first, | |
style: small, | |
), | |
), | |
), | |
large-4related: ( | |
columns: 2fr 1fr, | |
rows: auto auto auto auto, | |
cells: ( | |
1: 1 1 1 4, | |
), | |
column-gap: 3, | |
row-gap: 2, | |
item-style: ( | |
( | |
scope: first, | |
style: large, | |
), | |
( | |
scope: not-first, | |
type: related, | |
), | |
), | |
), | |
three: ( | |
columns: 1fr 1fr 1fr, | |
rows: auto, | |
), | |
four: ( | |
columns: 1fr 1fr 1fr 1fr, | |
rows: auto, | |
item-style: ( | |
( | |
type: opinion, | |
style: small, | |
scope: true, | |
), | |
), | |
), | |
five: ( | |
columns: 1fr 1fr 1fr, | |
rows: auto auto, | |
cells: ( | |
1: 1 1 2, | |
), | |
item-style: ( | |
( | |
type: opinion, | |
styl: small, | |
scope: not-first, | |
), | |
), | |
), | |
related: ( | |
columns: 1fr 1fr 1fr, | |
rows: auto auto, | |
column-gap: 5, | |
item-style: ( | |
( | |
type: related, | |
style: only-title, | |
scope: true, | |
), | |
), | |
), | |
article-aside: ( | |
columns: 1fr, | |
rows: auto auto auto auto auto, | |
item-style: ( | |
( | |
style: aside, | |
scope: true, | |
), | |
( | |
style: aside-small, | |
scope: not-first, | |
), | |
), | |
), | |
opinion: ( | |
columns: 1fr 1fr 1fr, | |
rows: auto, | |
item-style: ( | |
( | |
style: large, | |
scope: '.with-primary-opinion:first-child', | |
), | |
), | |
), | |
), | |
column-gap: 2, | |
row-gap: 2, | |
), | |
), | |
)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@function ie-grid-definition($grid, $gap) { | |
$result: (); | |
$size: length($grid); | |
@for $i from 1 through $size { | |
$result: append($result, nth($grid, $i)); | |
@if ($i < $size) { | |
$result: append($result, $gap); | |
} | |
} | |
@return $result; | |
} | |
@function ie-grid-cell-index($index) { | |
@return ($index - 1) * 2 + 1; | |
} | |
@function grid-parse-cell-definition($cell) { | |
@if (length($cell) < 2) { | |
@return null; | |
} | |
$column: nth($cell, 1); | |
$row: nth($cell, 2); | |
$column-span: null; | |
$row-span: null; | |
@if (length($cell) >= 3 and nth($cell, 3) != null) { | |
$column-span: nth($cell, 3); | |
} | |
@if (length($cell) >= 4 and nth($cell, 4) != null) { | |
$row-span: nth($cell, 4); | |
} | |
@return ( | |
column: $column, | |
column-span: $column-span, | |
row: $row, | |
row-span: $row-span, | |
); | |
} | |
%content-layout { | |
display: grid; | |
@include r-each-if('/content/layout/column-gap') { | |
grid-column-gap: v(r-get()); | |
} | |
@include r-each-if('/content/layout/row-gap') { | |
grid-row-gap: v(r-get()); | |
} | |
@include ie11() { | |
display: -ms-grid; | |
-ms-grid-column-align: stretch; | |
-ms-grid-row-align: stretch; | |
} | |
} | |
@import "layout/related"; | |
@import "layout/article-aside"; | |
@include r-with('/content/layout') { | |
$content-layout-template-names: map-keys(r-get('template', $id: $responsive-default-id)); | |
@each $template in $content-layout-template-names { | |
$prefix: 'template/#{$template}'; | |
.cbl-#{$template} { | |
@extend %content-layout; | |
@include r-each-if('#{$prefix}/columns') { | |
@if (not r-has('#{$prefix}/rows')) { | |
@error 'Columns and rows for grid template "#{$template}" should be defined simultaneously, check "#{r-id()}" responsive configuration'; | |
} | |
$columns: r-get(); | |
$rows: r-get('#{$prefix}/rows'); | |
grid-template-columns: $columns; | |
grid-template-rows: $rows; | |
@include ie11() { | |
$column-gap: v(r-get-effective('column-gap')); | |
$row-gap: v(r-get-effective('row-gap')); | |
-ms-grid-columns: ie-grid-definition($columns, $column-gap); | |
-ms-grid-rows: ie-grid-definition($rows, $row-gap); | |
} | |
} | |
@include r-each-if('#{$prefix}/column-gap') { | |
grid-column-gap: v(r-get()); | |
} | |
@include r-each-if('#{$prefix}/row-gap') { | |
grid-row-gap: v(r-get()); | |
} | |
.content-item { | |
@include r-each-if('#{$prefix}/cells') { | |
$cells: r-get(); | |
@each $index, $cell in $cells { | |
@if ($cell != null) { | |
&:nth-child(#{$index}) { | |
$definition: grid-parse-cell-definition($cell); | |
@if ($definition == null) { | |
@error 'Unsupported grid cell definition format "#{$cell}" is given for cell #{$index} in grid template "#{$template}" in "#{r-id()}" responsive configuration'; | |
} | |
$column: map-get($definition, column); | |
$row: map-get($definition, row); | |
$column-span: map-get($definition, column-span); | |
$row-span: map-get($definition, row-span); | |
@if ($column-span != null and $column-span > 1) { | |
grid-column: $column / span $column-span; | |
} @else { | |
grid-column: $column; | |
} | |
@if ($row-span != null and $row-span > 1) { | |
grid-row: $row / span $row-span; | |
} @else { | |
grid-row: $row; | |
} | |
} | |
} | |
} | |
} | |
// Handle enforcement of content item styles within layouts | |
@include r-each-if('#{$prefix}/item-style') { | |
$modifications: r-get(); | |
@each $params in $modifications { | |
$params: map-merge(( | |
type: true, | |
style: null, | |
scope: false, | |
), $params); | |
$type: map-get($params, type); | |
$style: map-get($params, style); | |
$scope: map-get($params, scope); | |
@if ($type and $style and $scope) { | |
$class: ''; | |
@if ($type != true and $type != 'content') { | |
$class: '.with-#{$type}'; | |
} | |
&#{$class} { | |
@if ($scope == first) { | |
$scope: ':first-child'; | |
}@if ($scope == last) { | |
$scope: ':last-child'; | |
} @if ($scope == not-first) { | |
$scope: ':not(:first-child)'; | |
} @else if ($scope == true) { | |
$scope: ''; | |
} | |
&#{$scope} { | |
@if ($type == true) { | |
$type: null; | |
} | |
@include apply-content-item-template($type, $style); | |
} | |
} | |
} | |
} | |
} | |
// IE 11 requires explicit binding of every child to particular grid cell | |
// because we use extra cell to define gaps between cells themselves | |
@include ie11() { | |
// It is only allowed to display explicitly mapped cells into IE 11 | |
// because of mapping issues, therefore we hide all content items | |
// and recover display for mapped ones | |
display: none; | |
@include r-each-if('/layout', $force-mq: true) { | |
$columns: r-get-effective('#{$prefix}/columns'); | |
$rows: r-get-effective('#{$prefix}/rows'); | |
$rows-count: length($rows); | |
$cells: r-get-effective('#{$prefix}/cells'); | |
$columns-count: length($columns); | |
// Create cells map to determine target cell position of every grid cell | |
$cells-map: (); | |
@for $r from 1 through $rows-count { | |
$rc: (); | |
@for $c from 1 through $columns-count { | |
$rc: map-merge($rc, ($c: null)); | |
} | |
$cells-map: map-merge($cells-map, ($r: $rc)); | |
} | |
// Map all explicit cells definition to the map | |
$mapped: (); | |
@each $index, $cell in $cells { | |
@if ($cell != null) { | |
&:nth-child(#{$index}) { | |
$definition: grid-parse-cell-definition($cell); | |
$column: map-get($definition, column); | |
$row: map-get($definition, row); | |
display: block; | |
-ms-grid-column: ie-grid-cell-index($column); | |
-ms-grid-row: ie-grid-cell-index($row); | |
$column-span: map-get($definition, column-span); | |
@if ($column-span != null) { | |
-ms-grid-column-span: ie-grid-cell-index($column-span); | |
} @else { | |
$column-span: 1; | |
} | |
$row-span: map-get($definition, row-span); | |
@if ($row-span != null) { | |
-ms-grid-row-span: ie-grid-cell-index($row-span); | |
} @else { | |
$row-span: 1; | |
} | |
@for $r from $row through ($row + $row-span - 1) { | |
@if (not map-has-key($cells-map, $r)) { | |
@error 'Grid cell row definition is out of bound for cell #{$index} in grid template "#{$template}" in "#{r-id()}" responsive configuration'; | |
} | |
$rc: map-get($cells-map, $r); | |
@for $c from $column through ($column + $column-span - 1) { | |
@if (not map-has-key($rc, $c)) { | |
@error 'Grid cell column definition is out of bound for cell #{$index} in grid template "#{$template}" in "#{r-id()}" responsive configuration'; | |
} | |
$rc: map-merge($rc, ($c: $index)); | |
} | |
$cells-map: map-merge($cells-map, ($r: $rc)); | |
} | |
$mapped: append($mapped, $index); | |
} | |
} | |
} | |
// Map unmapped cells into remaining places into grid | |
$unmapped: (); | |
@for $i from 1 through ($rows-count * $columns-count) { | |
@if (index($mapped, $i) == null) { | |
$unmapped: append($unmapped, $i); | |
} | |
} | |
$index: 1; | |
@for $r from 1 through $rows-count { | |
$rc: map-get($cells-map, $r); | |
@for $c from 1 through $columns-count { | |
$m: map-get($rc, $c); | |
@if ($m == null) { | |
@if ($index <= length($unmapped)) { | |
$cell-index: nth($unmapped, $index); | |
&:nth-child(#{$cell-index}) { | |
display: block; | |
-ms-grid-column: ie-grid-cell-index($c); | |
-ms-grid-row: ie-grid-cell-index($r); | |
} | |
$index: $index + 1; | |
} | |
} | |
$rc: map-merge($rc, ($c: null)); | |
} | |
$cells-map: map-merge($cells-map, ($r: $rc)); | |
} | |
} | |
} | |
} | |
// In a case if content layout is applied to a content block | |
// with separate background for each content item - | |
// allow certain content items to escape from defined grid offset | |
.content-block.cbg-item-color & { | |
@include r-offset('#{$prefix}/grid-offset', ph); | |
.content-item { | |
@include r-each-if('#{$prefix}/escape-offset', $force-mq: true) { | |
$cells: r-get(); | |
$offset: r-get-effective('#{$prefix}/grid-offset'); | |
@each $index in r-get() { | |
&:nth-child(#{$index}) { | |
@include offset($offset, nh); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment