[Bookmark] CSS: Using Indentation and Indentation

If several elements of a web page are located close to each other, then users get the feeling that these elements have something in common. The grouping of elements helps the user understand their relationship by evaluating the distance between them. If all the elements were located at the same distance from each other, it would be difficult for the user to browse through the page to find out which of them are related to each other and which are not. This article is dedicated to everything you need to know about setting distances between elements and about setting up internal spaces of elements. In particular, we will talk about in which situations it is worth using internal padding, and in which - external (margin).




CSS distance types


The distances between elements and their parts, customizable by CSS, are of two types. They, in relation to the element, are divided into internal and external. Imagine that we have an element. If inside it there is a certain distance between some of its parts, then this is an internal indent. If we are talking about the distance between the individual elements - this is the outer indent.


Inner space and outer space

In CSS, the distance between elements and their components can be adjusted as follows:

.element {
    padding: 1rem;
    margin-bottom: 1rem;
}

The property is paddingused here to adjust the indentation, and the property marginis used to configure the indentation. Everything is very simple. Truth? But adjusting distances in CSS can be very complicated if you work with components that have many small parts and children.

â–Ť Margin Property - Indent


The property is marginused to set the distance between individual elements. For example, the previous example used the CSS property margin-bottom: 1remto add the vertical distance between two elements located one above the other.

External indentation can be set for four sides of an element (top, right, bottom, left - top, right, bottom, left). Therefore, before moving on to examples and discussions of different ways of setting distances, it is important to shed light on some basic concepts.

â–Ť Collapse outer padding


If we describe the concept of “collapse of outer margins” in simple words, then we can say that this happens if two elements located one above the other have outer margins, and the indent of one of them is larger than the indent of the other. In this case, a larger indent will be used, and the smaller one will be ignored.


The greater indentation wins.

In the above diagram, the property is configured on the upper element and the propertymargin-bottomon the lower onemargin-top. The vertical distance between the elements corresponds to the larger of these indents.

In order to avoid this problem, it is recommended to configure the same indentation in all elements (as described here ). And here is another interesting fact. The CSS Tricks resource voted on the use of propertiesmargin-bottomandmargin-top. As it turned out, the propertymargin-bottomwon, taking 61% of the vote.

Here's how to solve this problem:

.element:not(:last-child) {
    margin-bottom: 1rem;
}

Using a CSS selector :notmakes it easy to remove the outer indent of the last child in order to get rid of unnecessary space between the elements.

→ Here is a demo of working with outer margins.

Another example related to collapsing outer margins is related to child and parent elements. Suppose you have the following HTML:

<div class="parent">
  <div class="child">I'm the child element</div>
</div>

Here are his styles:

.parent {
  margin: 50px auto 0 auto;
  width: 400px;
  height: 120px;
}

.child {
  margin: 50px 0;
}

Here's what the result of visualizing all of this looks like.


Child and parent

Note that the child abuts against the top of the parent. This is the result of the collapse of their outer margins. According to the W3C , there are several options for solving this problem:

  • Adding a property borderto the parent element.
  • Setting the property of a displaychild element to a value inline-block.

A more understandable solution to this problem would be to set the property of the padding-topparent element.


Setting the top indent of the parent element

â–Ť Negative Indent


A negative value can be used for any outer indentation. In some cases, this technique is very useful. Take a look at the following figure.


Results of setting the padding property of the parent element

The parent element has a propertypadding: 1rem. This causes the child to have offsets from the top, left, and right. But the child must be adjacent to the borders of the parent. Negative outer margins will help to achieve this.

.parent {
    padding: 1rem
}

.child {
    margin-left: -1rem;
    margin-right: -1rem;
    margin-top: -1rem;
}

That's what happened as a result of such stylization.


Negative outer margins of the child help to achieve the desired effect

→ Here is a demonstration

If you are interested in the topic of negative outer margins, I recommend this article.

â–ŤPadding property - inner padding


As already mentioned, the property paddingallows you to control the space inside the element. The purpose of applying this property depends on the situation in which it is used.

For example, it can be used to increase the space around links. This leads to an increase in clickable link space .


Indented in green

â–Ť Situations in which the padding property does not work


It is important to note that vertical indentation does not work with elements that have a property display: inline. For example, these are elements <span>and <a>. If you configure the property of paddingsuch an element, such a setting on this element will not work. This is just a friendly reminder that inline elements need to change a property display:

.element span {
    display: inline-block;
    padding-top: 1rem;
    padding-bottom: 1rem;
}

Space Between CSS Grid Layout Elements


In the CSS Grid, you can easily adjust the distance between columns and rows using the property grid-gap. This is an abbreviation for a property that defines the distance between columns and rows.


Distances between columns and rows

.element {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-gap: 16px; /*    16px     */
}

A complete record of these properties looks like this:

.element {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-row-gap: 24px;
    grid-column-gap: 16px;
}

The Space Between CSS Elements of a Flexbox Layout


There is one property suggested for grid and flexbox layouts. This is a property gap. Currently, only Firefox supports it .

.element {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}

Moreover, this property cannot be used with CSS @supportsto determine if it is supported, and to make appropriate decisions based on this. If you like this property - vote for adding it to Chrome.

Positioning Elements in CSS


Perhaps the positioning of elements cannot be directly attributed to ways to adjust the distance between them, but in some cases, positioning plays a role. For example, if there is an absolutely positioned child element that needs to be located at 16pxthe left and top edges of the parent element.

Consider the following example. There is a card on which there is an icon that needs to be placed at some distance from the top and left edges of the parent element. To achieve this effect, you can use the following style:

.category {
    position: absolute;
    left: 16px;
    top: 16px;
}



The distance between the boundaries of the parent and child elements is highlighted in green.

Use Scenarios and Case Studies


In this section, we will look at scenarios for using means for adjusting distances between elements. Something similar may well come across in your daily work with CSS.

â–Ť Header component



A component is a header that has the following settings: left and right margins, space around the logo, space around the navigation element, distance between the navigation element and user name

In this case, the header component has a logo, navigation area, and an area in which information is displayed about user profile. Can you guess what the stylization code of such an element should look like? Here, to make it easier, a schematic markup of such an element:

<header class="c-header">
  <h1 class="c-logo"><a href="#">Logo</a></h1>
  <div class="c-header__nav">
    <nav class="c-nav">
      <ul>
        <li><a href="#">...</a></li>
      </ul>
    </nav>
    <a href="#" class="c-user">
      <span>Ahmad</span>
      <img class="c-avatar" src="shadeed.jpg" alt="">
    </a>
  </div>
</header>



Inner and outer margins

Left and right margins are used. Their purpose is to ensure that the contents of the header do not cling to its edges.

.c-header {
    padding-left: 16px;
    padding-right: 16px;
}

When setting up navigation links, one must take into account the fact that each of them should have enough internal space both vertically and horizontally. Due to this, their clickable area will be large enough, which will improve the accessibility of the project.

.c-nav a {
    display: block;
    padding: 16px 8px;
}

If we talk about the distance between the elements, then you can use the property margin, or - you can change the property of the displayelements <li>to inline-block. Due to this, a small space is added between the elements lying on the same level, due to the fact that such elements are considered as symbols.

.c-nav li {
    /*     ,     */
    display: inline-block;
}

Finally, the username and avatar have a left outer indent.

.c-user img,
.c-user span {
    margin-left: 10px;
}

Please note that if you are creating a multilingual website, it is recommended to use logical CSS properties in this situation :

.c-user img,
.c-user span {
    margin-inline-start: 1rem;
}



The distances before and after the separator are not the same.

Note that the distances before and after the separator are not the same. The reason for this is that the width of the navigation block is not set. Instead, only internal indents are configured here. As a result, the width of the navigation elements depends on their content. Here are solutions to this problem:

  • Setting the minimum width for navigation items.
  • Increase horizontal indentation.
  • Adds an extra indent on the left side of the separator.

The best and easiest way is to use the third method, which is to configure the property margin-left:

.c-user {
    margin-left: 8px;
}

→ Here is a demo

â–Ť Distances in grid layouts - CSS Flexbox


Grid layouts are the place where technologies for adjusting the distance between elements are often used. Consider the following example.


Grid Layout

We need to adjust the distance between the rows and columns of the table. Here is the markup:

<div class="wrapper">
    <div class="grid grid--4">
        <div class="grid__item">
              <article class="card"><!--   --></article>
        </div>
        <div class="grid__item">
              <article class="card"><!--   --></article>
        </div>
        <!--   .. -->
    </div>
</div>

I usually prefer to keep the components in an encapsulated state and avoid setting up their outer indents. For this reason, I have an element grid_itemin which the card element will be located.

.grid--4 {
    display: flex;
    flex-wrap: wrap;
}

.grid__item {
    flex-basis: 25%;
    margin-bottom: 16px;
}

Thanks to this CSS code, there will be four cards in each line. Here is one possible way to adjust the distance between them:

.grid__item {
    flex-basis: calc(25% - 10px);
    margin-left: 10px;
    margin-bottom: 16px;
}

By using the CSS function, calc()indentation is subtracted from flex-basis. As you can see, this is not such a simple solution. I actually prefer the following:

  • Set the property of the grid item padding-left.
  • Set the parent element to have a negative outer margin margin-leftwith the same value as y padding-left.

I learned about this method many years ago, after reading here some article, the name of which has already forgotten (if you know what kind of article - please let me know).

.grid--4 {
    display: flex;
    flex-wrap: wrap;
    margin-left: -10px;
}

.grid__item {
    flex-basis: 25%;
    padding-left: 10px;
    margin-bottom: 16px;
}

The reason I used a negative value for for here margin-leftis because the first card has a property padding-leftthat, in reality, is not needed. As a result, I move the wrapper element to the left and get rid of unnecessary space.

→  Here is a working example.

Another similar idea is to use indentation and negative indentation. Here is an example from the Facebook site.


Inner and outer margins

Here is the CSS code illustrating this idea:

.wrapper {
    margin-left: -4px;
    margin-right: -4px;
}

.story {
    padding-left: 4px;
    padding-right: 4px;
}

â–ŤDistance in grid layouts - CSS Grid


And now - the best part! In CSS Grid-based layouts, the distance between elements is very convenient to adjust using the property grid-gap. In addition, you can not worry about the width of the elements and the lower external borders. CSS grid layout takes care of all this.

.grid--4 {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-gap: 1rem;
}

That's all. I believe no one will argue that setting up Grid layouts is easier and more understandable than setting up Flexbox layouts.

â–ŤSetting distance between elements only when necessary


In Grid layouts, I really like the fact that the property grid-gapis applied only when there must be some distance between the elements. Take a look at the following layout.


The layout of the grid in which the elements in the mobile environment are arranged vertically, and in the desktop - horizontally.

There is a section of the site with two cards. I need them to be separated both in a mobile environment, with a vertical arrangement of cards, and in a desktop, with their horizontal arrangement. Without CSS Grid, such layout flexibility is impossible to achieve. Take a look at the following code:

.card:not(:last-child) {
    margin-bottom: 16px;
}

@media (min-width: 700px) {
    .card:not(:last-child) {
        margin-bottom: 0;
        margin-left: 1rem;
    }
}

Not very convenient. Truth? What about the next style?

.card-wrapper {
    display: grid;
    grid-template-columns: 1fr;
    grid-gap: 1rem;
}

@media (min-width: 700px) {
    .card-wrapper {
        grid-template-columns: 1fr 1fr;
    }
}

It is done! And everything is much simpler.

â–ŤWork with bottom outer indentation


Suppose that we have the following components located one above the other. Each of them has a lower outer indent.


A set of components arranged horizontally

Note that there is a bottom outer margin for the last element. And this is wrong, since indents should be present only between elements.

You can fix this problem by resorting to one of the solutions that we will now analyze.

Solution # 1: CSS selector: not


.element:not(:last-child) {
    margin-bottom: 16px;
}

Solution No. 2: a combination of neighboring elements of the same level


.element + .element {
    margin-top: 16px;
}

Decision analysis


Although solution # 1 seems more attractive, it has the following disadvantages:

  • It leads to CSS specific issues. It cannot be redefined until a selector is used :not.
  • It does not apply when there is more than one column of items. This is illustrated below.


Two columns of elements and the problem of solution No. 1

If we talk about solution No. 2, then its application does not lead to problems with specificity. True, this solution is also suitable only in those cases when it comes to a single column of elements.

In this situation, it is best to resort to the decision to remove unnecessary space by adding a negative external indentation to the parent element:

.wrapper {
    margin-bottom: -16px;
}

Here the following happens. Thanks to this setting, the element is shifted downward by a distance equal to the specified external indentation. But here you should be careful not to set such an external indent when using which the elements would overlap.

â–Ť Component Card


Now I want to discuss in detail the settings of the component cards. Perhaps in the end I will get a whole book about it. Here I will consider a universal pattern for configuring cards and talk about how to manage them.


Component card (if you feel like eating - I'm sorry)

Think about where exactly in this card the distance between elements and their parts is used. Here is my answer to this question.


Inner and outer margins

Here is the markup:

<article class="card">
    <a href="#">
      <div class="card__thumb"><img src="food.jpg" alt=""></div>
      <div class="card__content">
        <h3 class="card__title">Cinnamon Rolls</font></h3>
        <p class="card__author">Chef Ahmad</p>
        <div class="card__rating"><span>4.9</span></div>
        <div class="card__meta"><!-- --></div>
      </div>
    </a>
</article>

Here is the class style card__content:

.card__content {
    padding: 10px;
}

Thanks to the indentation set here, the offset for all children will be set. Then set up the outer margins:

.card__title,
.card__author,
.card__rating {
  margin-bottom: 10px;
}

When setting up the separation of rating and information, I used the border:

.card__meta {
    padding-top: 10px;
    border-top: 1px solid #e9e9e9;
}

But here we are faced with a problem! The border is not tied to the edges, which is due to the card__contentindentation of the parent element with the class .


The separator is not tied to the edge.

You, perhaps, have already guessed that negative indents will help us here:

.card__meta {
    padding-top: 10px;
    border-top: 1px solid #e9e9e9;
    margin: 0 -10px;
}

But here again, something went wrong. Now the text has stuck to the edge of the card.


The separator is normal, but the contents of the card are not located correctly.

In order to solve this problem, you need to configure the left and right indents for the contents of the card.

.card__meta {
    padding: 10px 10px 0 10px;
    border-top: 1px solid #e9e9e9;
    margin: 0 -10px;
}



The card is configured as it should

→ Here is an example

â–Ť Content of articles


I am sure that what we are going to talk about here is a very, very common situation. The point here is that the content of articles usually goes to pages from CMS (Content Management System - content management system), or is generated automatically based on Markdown files. You cannot specify element classes here.

Consider the following example, which shows markup containing a mixture of headings, paragraphs, and images.

<div class="wrapper">
  <h1>Spacing Elements in CSS</h1>
  <p><!-- content --></p>
  <h2><font color="#3AC1EF">Types of Spacing</font></h2>
  <img src="spacing-1.png" alt="">
  <p><!-- content --></p> 
  <p><!-- content --></p> 
  <h2><font color="#3AC1EF">Use Cases</font></h2>
  <p><!-- content --></p> 
  <h3><font color="#3AC1EF">â–ŤCard Component</font></h3> 
  <img src="use-case-card-2.png" alt="">
</div>

In order to bring it all to a decent appearance, the distances between the elements should be uniform and should be used responsibly. While working on this example, I borrowed some styles from type-scale.com .

h1, h2, h3, h4, h5 {
  margin: 2.75rem 0 1.05rem;
}

h1 {
  margin-top: 0;
}

img {
  margin-bottom: 0.5rem;
}

Here is a diagram of the page with the article text.


Page layout and application of margin-top and margin-bottom properties

If an element is<p>followed by a heading, for example, a headingTypes of Spacing, then the property of themargin-bottomelement<p>will be ignored. This, as you can guess, is a consequence of the collapse of the outer margins.

→ Here is an example

â–Ť External indentation, as applicable


Take a look at the following layout.


Elements in normal condition and in a situation of running out of space

Elements do not look very good when they are too close to each other. I created this layout using Flexbox. This technique is called “Alignment Shifting Wrapping”. I found out about her name from here .

.element {
    display: flex;
    flex-wrap: wrap;
}

As a result of applying this technique, line wrapping is performed if the viewing area is less than a certain limit. Here is how it looks.


Child elements are on new lines.

Here you need to deal with an intermediate situation in which two elements are still next to each other, but the distance between them is zero. In this case, I prefer to resort to the propertymargin-right, which prevents the elements from touching each other and speeds up the responseflex-wrap.


Elements do not touch each other

â–ŤCSS property writing-mode


First we quote MDN : “The property writing-modesets the horizontal or vertical position of the text, as well as the block direction.”

Have you ever thought about how external indents should behave when they are used with an element whose property writing-modeis different from the standard? Consider the following example.


Card with a vertical header.

Here are the styles:

.wrapper {
    /*              */
    display: flex;
}

.title {
    writing-mode: vertical-lr;
    margin-right: 16px;
}

The header is rotated 90 degrees. There should be an empty space between it and the image. As it turned out, the property margin-rightshows itself perfectly with different values ​​of the property writing-mode.

→ Here is an example.

I believe we have covered enough indentation scenarios. Now consider some interesting concepts.

Component encapsulation


Large design systems contain many components. Will it be logical to adjust their outer margins?

Consider the following example.


Buttons

<button class="button">Save Changes</button>
<button class="button button-outline">Discard</button>

Where do I need to adjust the distance between the buttons? Do I need to configure some properties of the left or right button? Maybe you can use a combination of neighboring elements of the same level?

.button + .button {
    margin-left: 1rem;
}

There is nothing good about it. What if there is only one button? And how will it work on a mobile device, in the case when the buttons are located vertically, and not horizontally? In general, here we are faced with many difficult questions.

â–ŤUsing abstracted components


The solution to the above problems is the use of abstracted components, which are used to place other components in them. This, as said here , is a bit of a shift in responsibility for managing padding to the parent element. We rethink the previous example in the light of this idea.


Parent and child components

<div class="list">
    <div class="list__item">
        <button class="button">Save Changes</button>
    </div>
    <div class="list__item">
        <button class="button button-outline">Discard</button>
    </div>
</div>

Please note that there are wrapper elements. Each button has its own wrapper.

.list {
    display: flex;
    align-items: center;
    margin-left: -1rem; /*       */
}

.list__item {
    margin-left: 1rem;
}

That's all! And what's more, this concept is easy to apply to any JavaScript framework. For instance:

<List>
  <Button>Save Changes</Button>
  <Button outline>Discard</Button>
</List>

And the used JS tool should put each element in its own wrapper.

Components Used as Separators


If you doubt that you read the heading correctly - do not hesitate. We are talking about components used as separators. In particular, here I refer to this article, which discusses the concept that avoids the use of external indentation and uses separator components instead.

Imagine that in a certain section of the site you need a left outer indent of size 24px. At the same time, the following requirements are put forward to indentation:

  • External indentation should not be configured directly at the component, since it is part of an already created design system.
  • Indentation must be flexible. On one page it can have a size X, and on the other - a size Y.

I first noticed this trick while exploring the new Facebook design .


Facebook Design Separator Element

Here is used as a separator element<div>with an inline stylewidth: 16px. Its sole purpose is to add empty space between the left element and the container element.

Here is a quote from this React training manual: “But in the real world, we need spaces defined outside of components to arrange components into pages and scenes. It is here that the settings of the outer indentation make their way into the component code to adjust the distances between the components when they are assembled.

I agree with that. In a large design system, adding indentation to components will be irrational. This will result in a not-so-good-looking code.

â–Ť Separator component issues


Now that you’ve familiarized yourself with the idea of ​​separator components, let’s talk about some of the problems that are expected to occur when working with them. Here are the questions I have been thinking about:

  • How does a separator component take up space in a parent component? How does he behave in horizontal and vertical layouts? For example, how would such a component separate components vertically and horizontally?
  • Do I need to style these components based on the property displayof the parent component (Flexbox, Grid)?

Let us examine these questions.

â–ŤSizes of separator components


You can create a separator component that accepts various parameters. I am not a JavaScript developer, but I think this is what is called “props”. Consider the following example, taken from here .

There is a separator component located between Headerand Section.

<Header />
<Spacer mb={4} />
<Section />

And here is a slightly different situation. Here, the separator is used to create an automatically adjustable distance between the logo (component Logo) and the navigation area represented by the components Link.

<Flex>
  <Logo />
  <Spacer m="auto" />
  <Link>Beep</Link>
  <Link>Boop</Link>
</Flex>

It might seem that implementing such a separator using CSS is very simple, and that it’s enough to use the design justify-content: space-between. But what if you need to change the design? In this case, you have to change the stylization.

Take a look at the following example. Does this code look flexible?

<Flex>
  <Logo />
  <Link>Beep</Link>
  <Link>Boop</Link>
  <Spacer m="auto" />
  <Link>Boop</Link>
</Flex>

In this case, stylization needs to be changed.

In terms of size, we can say that the size of the separator can be adjusted based on the size of the parent element. In the above case, it may make sense to create a property growthat is set to a value in CSS flex-grow: 1.

<Flex>
  <Spacer grow="1" />
</Flex>

â–ŤUse of pseudo-elements


Another idea that came to my mind is to use pseudo-elements to create separators.

.element:after {
    content: "";
    display: block;
    height: 32px;
}

Maybe we have the opportunity to make a pseudo-element a separator, and not use a separate element for this? For instance:

<Header spacer="below" type="pseudo" length="32">
  <Logo />
  <Link>Home</Link>
  <Link>About</Link>
  <Link>Contact</Link>
</Header>

So far, I have not used separator components in my projects. But I'm looking for scenarios in which they could be useful to me.

CSS math functions min (), max (), clamp ()


Can indentation be dynamic? For example, is it possible to use such an indentation, the minimum and maximum size of which depends on the width of the viewing area? I can answer this question positively. CSS functions, according to CanIUse data , are supported by all leading browsers.

Recall Grid layouts and talk about how dynamic indentation can be used in them.

.wrapper {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-gap: min(2vmax, 32px);
}

Construction min(2vmax, 32px)means the following: use a distance equal 2vmaxto but not exceeding 32px.

→  Here is a video demonstration of such a layout

→  Here is an example.

Such flexibility is truly amazing. It gives us many opportunities to create dynamic and flexible layouts of web pages.

Summary


In this article, we examined the features of adjusting the distances between elements of web pages using CSS and talked about managing the internal space of elements. We hope you find it useful what you learned today.

Dear readers! What tools do you use most often to adjust the distance between web page elements?


All Articles