DEV Community

Cover image for Bright moments in Web development: A CSS journey
Mag
Mag

Posted on

Bright moments in Web development: A CSS journey

Introduced in 1996, CSS was designed to separate content from design. This separation allowed developers to maintain and update web styles more efficiently without altering the HTML structure. The early versions of CSS focused primarily on basic typography and color styling. As the web grew, so did the capabilities of CSS, expanding to include layouts, positioning, and dimensions.

Each iteration not only enhanced the visual capabilities of the web but also introduced more efficient, elegant solutions for common design challenges. This article explores key moments that have brought me those "aha" moments, revealing how simple CSS properties and techniques can be used in surprisingly effective ways.

The Art of Spacing: Paddings and Margins

Let's explore a common layout scenario: arranging blocks in columns and rows using CSS.

Padding and margin are two of the most commonly used properties that manage space in web design. Margin is the space around elements; it's external and used to separate the element from others.

Let's take a look at the first approach:

<div class="parent">
  <div class="item">Block 1</div>
  <div class="item">Block 2</div>
  <div class="item">Block 3</div>
  <div class="item">Block 4</div>
  <div class="item">Block 5</div>
</div>

<p>next content</p>
Enter fullscreen mode Exit fullscreen mode
.parent {
  display: table;
  width: 100%;
}
.item {
  margin-left: 15px;
  margin-bottom: 30px;
  width: 280px;
  float: left;
}
Enter fullscreen mode Exit fullscreen mode

3 in row, 2 columns

We use the display: table property to dynamically adjust the .parent block’s height according to the space occupied by its child elements. Consider the following example without this property:

the "next content" after blocks without display table

Downside of this approach:

Adjusting the layout of the .item element becomes complex under this approach, especially when the width of the parent container changes. The width and margin-left of the .item element need continuous recalibration according to the formula: parentWidth — (itemWidth * 3) — ((gap * 4) / 3).

Applying padding to the parent element introduces further complexity:

  • When padding exceeds the gap, apply padding-left and padding-right using the calculation: padding  —  gap
  • When padding is less than the gap, recalculate the width of the .item elements

Another downside is the extra space that appears after the elements.


When Bootstrap emerged, I experienced a true ‘aha’ moment: the realization that we could use negative margins to adjust side paddings and gaps effectively. Here’s an example to illustrate this technique:

<div class="container">
  <div class="parent">
    <div class="item-wrap"><div class="item">Block 1</div></div>
    <div class="item-wrap"><div class="item">Block 2</div></div>
    <div class="item-wrap"><div class="item">Block 3</div></div>
    <div class="item-wrap"><div class="item">Block 4</div></div>
    <div class="item-wrap"><div class="item">Block 5</div></div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode
.container {
  box-sizing: border-box;
  width: 900px;
  margin-left: auto;
  margin-right: auto;
  padding-left: 15px;
  padding-right: 15px;
}

.parent {
  margin-left: -7.5px;
  margin-right: -7.5px;
}
.parent::after {
  display: block;
  clear: both;
  content: "";
}
Enter fullscreen mode Exit fullscreen mode

Visually, the layout appears similar, but it improves significantly with the addition of padding to the container, adjustments to the item’s width, and the spacing between blocks.

Downsides:

  • Utilizing the ::after pseudo-element to adjust the parent’s height based on its inner elements is a makeshift solution that can lead to maintenance challenges.
  • The use of fractional pixel measurements, such as 7.5px (half of a 15px gap), complicates precision in layout and can result in inconsistent rendering across different displays.

Obviously we could use flexboxes to replace the pseudo-element, float and extra DOM elements, it’s more interesting to focus on a key feature: CSS custom variables with the calc() function.

<div class="container">
  <div class="parent">
    <div class="item-wrap"><div class="item">Block 1</div></div>
    <div class="item-wrap"><div class="item">Block 2</div></div>
    <div class="item-wrap"><div class="item">Block 3</div></div>
    <div class="item-wrap"><div class="item">Block 4</div></div>
    <div class="item-wrap"><div class="item">Block 5</div></div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode
.container {
  box-sizing: border-box;
  width: 900px;
  margin-left: auto;
  margin-right: auto;
  padding-left: 15px;
  padding-right: 15px;
}
.parent {
  --gap: 15px;

  margin-left: calc(var(--gap) / -2);
  margin-right: calc(var(--gap) / -2);
  display: flex;
  flex-wrap: wrap;
}
.item-wrap {
  box-sizing: border-box;
  margin-bottom: 30px;
  padding-left: calc(var(--gap) / 2);
  padding-right: calc(var(--gap) / 2);
  width: calc(100% / 3);
}
Enter fullscreen mode Exit fullscreen mode

This approach may appear outdated as modern grid systems provide simpler, more efficient solutions. Let's conclude this section by exploring a proper alternative:

<div class="container">
  <div class="parent">
    <div class="item">Block 1</div>
    <div class="item">Block 2</div>
    <div class="item">Block 3</div>
    <div class="item">Block 4</div>
    <div class="item">Block 5</div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode
.container {
  box-sizing: border-box;
  width: 900px;
  margin: 0 auto;
  padding: 0 15px;
}
.parent {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 15px;
  row-gap: 30px;
}
Enter fullscreen mode Exit fullscreen mode

Mastering Layouts: Positioning of Block Elements

Another classic task frequently asked in interviews involves positioning a block at the center of the screen:

<h2>Variant with inline-block</h2>

<div class="container">
  <div class="container__child container__child_v1">
    <div class="box"></div>
    <div class="box"></div>
  </div>
</div>

<h3>inline-block without space</h3>

<div class="container">
  <div class="container__child container__child_v1"><div class="box"></div><div class="box"></div></div>
</div>

<h2>Variant with margin auto</h2>

<div class="container">
  <div class="container__child container__child_v2">
    <div class="box"></div>
    <div class="box"></div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode
.container {
  box-sizing: border-box;
  width: 100%;
  display: table;
}
.container__child {
  height: 180px;
  display: table-cell;
  vertical-align: middle;
}

.container__child_v1 {
  text-align: center;
}
.container__child_v1 .box {
  display: inline-block;
}

.container__child_v2 .box {
  margin-left: auto;
  margin-right: auto;
}

.box {
  width: 68px;
  height: 68px;
}
Enter fullscreen mode Exit fullscreen mode

multiple examples with inline-block style

Downsides:

For the first variant, adding another box will cause the subsequent element to align in a row, with extra space introduced due to the inline-block being treated similarly to text. It’s important to consider two different approaches when arranging elements in columns versus rows.

A minor yet noteworthy detail is the addition of an extra DOM element required to apply the vertical-align rule.

Now, let’s explore another 'aha' moment that was truly mind-blowing for me the first time I encountered it:

<div class="container">
  <div class="box"></div>
</div>
Enter fullscreen mode Exit fullscreen mode
.container {
  height: 240px;
  position: relative;
}
.box {
  position: absolute;
  left: 50%;
  top: 50%;
  margin-left: -34px;
  margin-top: -34px;
  width: 68px;
  height: 68px;
}
Enter fullscreen mode Exit fullscreen mode

single box in the middle of the screen

Indeed, it might seem like a simple layering detail, but the technique of positioning an element at 50% and then adjusting it with a negative margin was quite astonishing to me at the time.

The caveat, of course, is the need to meticulously monitor the width and height of the box to ensure proper alignment by negative margin. However, there’s a clever workaround for this issue:

.box {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 68px;
  height: 68px;
}
Enter fullscreen mode Exit fullscreen mode

The transform property combined with translate achieves a similar effect, but it simplifies the process by automatically calculating 50% of the element's width for the X-axis and 50% of its height for the Y-axis.

Top comments (0)