Bright moments in Web development: A CSS journey
Tags: css, html, webdev
Published: 2024-05-13 19:46:01

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:

```html
<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>
```
```css
.parent {
  display: table;
  width: 100%;
}
.item {
  margin-left: 15px;
  margin-bottom: 30px;
  width: 280px;
  float: left;
}
```

![3 in row, 2 columns](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9lcl9zakue2uojnzgtil.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nszx186i2s67hzt7tluo.png)

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:

```html
<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>
```
```css
.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: "";
}
```

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.

```html
<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>
```
```css
.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);
}
```

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

```html
<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>
```
```css
.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;
}
```

## Mastering Layouts: Positioning of Block Elements

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

```html
<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>
```
```css
.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;
}
```

![multiple examples with inline-block style](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dfrc8fufxasbxpjg01ih.png)

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:

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

![single box in the middle of the screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uu2ezmcvhu7v1iqssimx.png)

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:

```css
.box {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 68px;
  height: 68px;
}
```

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.