Using Fixed CSS Grid Layout
Prequisites
The guide assumes that the grid is fixed CSS grid layout and uses 12 columns for each breakpoint. Learn more about configuring your grid here.
$grid-type: 'grid';
$grid-fluid: false;
$grid-layouts: (
'xs': (
'container': 100%,
'columns': 12,
'gap': 15px,
'margin': 15px,
),
'sm': (
'container': 540px,
),
'md': (
'container': 720px,
),
'lg': (
'container': 960px,
),
'xl': (
'container': 1140px,
),
'xxl': (
'container': 1560px,
),
);
Introduction
Fixed CSS Grid differs from flexbox solution in that the layout is created in the SCSS, not twig or html files.
It utilizes the CSS Grid in order to create the layout for each website's component.
It brings the benefit of cleaner structure and readability of .twig and .html files and minimises the chance of repeating the same code.
Layouts
The layout is a visual representation of grid elements written in the order they appear to the user.
It is similar to the native CSS 3's grid-template-areas property, but much more extensible, giving you ability to repeat certain element in shorter way.
Also, you can create multiple layouts in one declaration of the grid() mixin!
<div class="parent">
<div class="parent__element">
<p>Element</p>
</div>
</div>
The problem
Imagine you have 12 columns layout, in your website, and want to extend the element over all of them.
In native CSS you would do like so:
.parent {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-areas:
'element element element element element element element element element element element';
&__element {
grid-area: element;
}
}
It does not seem very readable, and it's hard to tell exactly how many columns does the .parent__element take.
You could potentially use the grid-column property and grid-row properties on the .parent__element itself, but it prevents
you from controlling the .parent__element from the .parent scope.
The solution
Loonar comes with a handy grid() mixin, which allows you to create a grid of multiple layouts in one declaration.
It utilises both .parent scope and grid-column / grid-row properties on the .parent__element itself.
Here's an example, how this layout would look like in Loonar!
.parent {
@include grid((
xs: (
'12(element)',
)
));
}
The only thing you need to remember is to follow the BEM methodology, no need to pass the parent in the name of the element. It'll be automatically added by Loonar.
Manipulating the layout based on viewport size
As you have seen in the previous example, we created a template for the xs breakpoint.
This breakpoint name is extracted from the breakpoint you have already defined in the $breakpoints map, when configuring the project.
Since it's the smallest breakpoint it will be triggered initially, without any @media queries.
Your layout will change many times, depending on the design of your website. Whenever it changes, and you want to re-position the elements, you can do so by simply providing the template for higher breakpoint.
In this example, we'll have another element in our layout. Both of them should be placed next to each other whenever the viewport reaches $md breakpoint, but initially they should be placed below each other.
<div class="parent">
<div class="parent__element-one">
<p>Element one</p>
</div>
<div class="parent__element-two">
<p>Element two</p>
</div>
</div>
.parent {
@include grid((
xs: (
'12(element-one)',
'12(element-two)',
),
md: (
'6(element-one) 6(element-two)',
),
));
}
Spacing between elements
Sometimes, you'd like to increase or decrease the gap between elements.
Some designs may have 0px gap between elements, or maybe you have the need to push certain element by a column or two.
The grid() mixin allows you to do that by adding a . (dot).
You only need to remember, not to exceed the total number of columns.
.parent {
@include grid((
xs: (
'12(element-one)',
'12(element-two)',
),
md: (
'6(element-one) . 5(element-two)',
),
));
}
If you are in need to push the element by more than one column, you can do so the same way as specifying the number of columns for an element.
.parent {
@include grid((
// ...
md: (
'5(element-one) 2(.) 5(element-two)',
),
));
}
Nested layouts
In some cases, you might need to include layout in another layout.
These are nested layouts. Because they are not specifically related to the .parent, the scope now changes to the .parent__element itself.
To make the nested layout work, you need to pass the scope name as the second argument to the grid() mixin.
<div class="parent">
<div class="parent__element-one">
<p>Element one</p>
</div>
<div class="parent__element-two">
<div class="element-two__child-one">
<p>Child one</p>
</div>
<div class="element-two__child-two">
<p>Child two</p>
</div>
</div>
</div>
.parent {
@include grid((
xs: (
'12(element-one)',
'12(element-two)', // element-two has 12 columns initially
),ą
md: (
'6(element-one) . 5(element-two)', // element-two has 5 columns when reached `md`
),
));
&__element-two {
@include grid((
xs: (
'6(child-one) 6(child-two)', // 6 + 6 = 12 initially
),
md: (
'3(child-one) 2(child-two)', // 3 + 2 = 5 when reached `md`
),
), '.element-two');
}
}