📜 ⬆️ ⬇️

Vertical padding between columns using Sass using the bootstrap grid example

Virtually any site can not do without blocks of streaming elements, such as: a list of news, products, gallery photos. Such elements are mainly output by the template engine in a loop; they occupy an equal number of columns and an unexpected number of rows. If such elements move to the second line, then between them it is necessary to provide vertical indents so that they do not shrink. Even if on the model the designer for beauty brought out only one row, on the layout it is necessary to provide an increase in the number of such elements.
Vertical padding between columns
The task seems to be easy, what is there to talk about at all. But let's analyze all the same ways to solve this problem, as there are pitfalls.

Indent for each item


Imagine that our markup is:
<ul class="gallery"> <li class="gallery__image"></li> </ul> 

But the problem here is that the parent block itself will recede from the lower ones by 20px, it will not be isolated from the external environment, it will affect the geometry of the neighboring blocks. It will be difficult to transfer to other places of the site or to other projects. In short, the gallery block will not be independent.

As a result, we need to get something similar to the internal indents of the table, where they are applied only inside the table and do not go outside.
')

Negative indent for block


For each element, we make the vertical indent for the parent and the negative vertical indent of the same size.
 .gallery{ margin-top: -20px } .gallery__image{ margin-top: 20px } 

Everything seems to be fine, but if the block is in the area that the block covers the interactive element, for example, a link, then the block will block it. These links will not work on the screen.
Negative indent for block
You can get out of this situation. It is necessary to wrap the gallery block in another block, which is set to overflow: hidden and it will cut off all the overflow.
 .gallery{ overflow: hidden; } .gallery__inner{ margin-top: -20px } .gallery__image{ margin-top: 20px } 

But there is another problem. All overflow is clipped, and this limits many design decisions. For example, a block shadow when hovering on a photo, labels that can be added to an item, for example, the “Sales hit” label for a product. Also, when you hover on an element, a drop-down block may appear with detailed information and so on.

Indent for each item except n first


Ideally, you should specify the top indent for all elements except the first row. This can be done using the nth-child pseudo-class.

But if you specify statically, then the solution will not be flexible and with a change in the number of columns you will need to change the rules, and this is not just not convenient, but completely unsuitable given the changes in columns during media queries.

But when using preprocessors, this solution can be made flexible, which is what I want to demonstrate to you. I took the Bootstrap grid as a basis, that is, each photo gallery from us is placed in the grid column. I used Sass as a preprocessor. But this approach can be safely applied to other grids and preprocessors.

Let me remind you that the columns in the bootstrap grid are recorded by the following classes:
col-xs- *
col-sm- *
col-md- *
col-lg- *

Let's imagine that our gallery is enclosed in 3 columns on a medium sized screen, that is, col-md-4. For universality, we will indent the columns of the grid with the row-vertical-indent modifier assigned.
 <div class=”row row--vertical-indent”> <div clas=”col-md-4”> <div class=”gallery-item”> <img...> </div> </div> </div> 

Now we write Sass styles.
 .row-vertical-indent{ & > [class~="col-md-4"]:nth-child(n+4){ padding-top: 20px; } } 

As a result, all elements starting from the 4th will be indented from above. The first 3 will be indented.

Let us now expand the possibilities and consider any number of columns on medium-sized screens.
 .row-vertical-indent{ @for $i from 1 through $grid-columns{ $nth-element: floor(($grid-columns / $i) + 1); & > [class~="col-md-#{$i}"]:nth-child(n+#{$nth-element}) { padding-top: 20px; } } } 

The variable $ grid-columns is an internal variable of bootstrap, which is assigned the number of grid columns. The default is 12.

We run over the cycle in all possible numbers of columns and assign indents for those elements that do not fit in 12 columns, respectively, go to the second row.

But we also do not know how many columns will be for other break-points, so you need to go through all the options for media queries.

Create an object (I can not get used to the terminology of “map”) of media queries.
The key is the break-point symbol in the class name, that is, col-xs .., col-sm .., col-md ...
Meaning - this is the media turns themselves for each break-point.
 $break-points: ( 'xs': '(max-width: #{$screen-xs-max})', 'sm': '(min-width: #{$screen-sm-min}) and (max-width: #{$screen-sm-max})', 'md': '(min-width: #{$screen-md-min}) and (max-width: #{$screen-md-max})', 'lg': '(min-width: #{$screen-lg-min})' ); 

Then we go over this object and for each iteration we apply the previous construction, but for a specific media turn.
 @each $key, $val in $break-points{ @media #{$val}{ @for $i from 1 through $grid-columns{ $nth-element: floor(($grid-columns / $i) + 1); & > [class~="col-#{$key}-#{$i}"]:nth-child(n+#{$nth-element}){ padding-top: $gutter; } } } } 

Do not forget in the name of the selectors instead of md to prescribe the value of the key object. # {$ key}

Then I propose to wrap all this in an admixture and set the amount of indent dynamically through an argument.

As a result, we have such an admixture, which can expand the capabilities of the bootstrap mesh.
 @mixin grid-vetical-gutter($gutter){ $break-points: ( 'xs': '(max-width: #{$screen-xs-max}) ', 'sm': '(min-width: #{$screen-sm-min}) and (max-width: #{$screen-sm-max})', 'md': '(min-width: #{$screen-md-min}) and (max-width: #{$screen-md-max})', 'lg': '(min-width: #{$screen-lg-min})' ); @each $key, $val in $break-points{ @media #{$val}{ @for $i from 1 through $grid-columns{ $nth-element: floor(($grid-columns / $i) + 1); & > [class~="col-#{$key}-#{$i}"]:nth-child(n+#{$nth-element}){ padding-top: $gutter; } } } } } 

Now, for the desired class, we simply call the admixture by passing indentation.
 .row-vertical-indent{ @include grid-vetical-gutter(20px) } 

Limitations and limitations of this approach:

1 - It works correctly only for the same number of columns in a row.
That is, for a dynamic stream of columns that are displayed in a cycle (product catalog, news, gallery, etc.).

For a static number of columns, for example, for marking the page itself, such a solution may not work correctly and in principle is not necessary so as not to clutter up the compiled CSS code. In this case, it is even more convenient for individual classes to add indentation where necessary.

2 - It is necessary to specify all break points for the column.
My solution does not provide for a mobile first approach and the styles will not be applied on a screen for which the number of columns is not indicated.

In bootstrap, such a record means that there will be 3 columns for all sizes starting with sm.
But when using vertical indents, the number of columns must be specified for all sizes, that is, the record will look like this
<div class == ”col-xs-12 col-sm-4 col-md-4 col-lg-4”>

I tried to provide a mobile first approach, but I ran into a terrible haemorrhoid associated with the redefinition of styles that scored as a result. If anyone succeeds, let me know, I will be very grateful.

3 - Tin in compiled CSS.
If someone has to edit the compiled css-file, then there will be a lot of garbage. I personally do not matter, but you never know.

Source: https://habr.com/ru/post/266113/


All Articles