Saturday, September 16, 2023
HomeCSSRebuilding a featured information part with trendy CSS: Vox information

Rebuilding a featured information part with trendy CSS: Vox information


a structure at first look may indicate that it’s simple and easy to construct. The second you begin constructing the preliminary structure, you’ll face challenges that you simply didn’t take into consideration in your preliminary have a look at the design.

On this article, I’ll rethink tips on how to construct the featured information part on Vox.com and attempt to see if trendy CSS might be useful or not. For instance, do we have to use container queries? Or fluid sizing? That’s the objective of this text. It’s a journey as I believe aloud about constructing a structure that appears easy.

Article sequence

Desk of contents

Analyzing the part

Within the largest viewport, now we have a 3 columns structure. Two of the columns take 25% of the width, and the center one takes 50%. Here’s a visible that reveals them:

Now that now we have an thought concerning the columns, let’s check out the parts inside them.

It would look a bit complicated to identify the variations, however I’ll stroll you thru every change so we are able to have an thought about what’s altering on every viewport dimension.

Adjustments from the massive to medium

  • Featured part: virtually the identical, however with a special font dimension that’s altering based mostly on the viewport width.
  • Blue part: the font dimension of every card title bought smaller.
  • Pink part:
    • The primary article’s thumb is hidden.
    • Format is modified from one column to 3 columns.
    • Including a separator on the prime of the part.

Adjustments from medium to small

  • All articles will swap to the horizontal type with the thumbnail proven for every one.
  • The featured article will turn into horizontal, however with a bigger thumbnail to distinguish it from the remainder of the articles.

With that in thoughts, now we have a fundamental define of how the structure is behaving on totally different viewport sizes. The subsequent step is to construct the structure and deal with the ordering of the columns.

Constructing the principle structure

In vox.com, CSS flexbox is getting used to deal with the structure. I’m not a fan of utilizing flexbox for such a objective as this feels extra like a CSS grid use case. I consider the Vox staff used flexbox because it was higher supported on the time of constructing the structure.

@media (min-width: 880px)
    .c-newspaper__column {
        width: 22.5%;
        padding: 0 16px;
    }
}

The CSS above is accountable for the next:

  • Setting the width of the column. Utilizing width property for that works fantastic, however we are able to additionally use the flex property.
  • Including padding on the left and proper sides is an previous approach to introduce a niche between columns. Now now we have the hole property!

We will use the flex property like this:

@media (min-width: 880px)
    .c-newspaper__column {
        flex: 0 0 22.5%;
        padding: 0 16px;
    }
}

..however the excellent news is that we don’t have to make use of flexbox.

These days, CSS grid has wonderful browser help and it’s simpler to take care of the sizing and spacing. Additionally, I’m an advocate of utilizing grid for layouts and flexbox for parts.

Take into account the next HTML markup:

<div class="c-newspaper">
  
  <div class="c-newspaper__col">1</div>

  
  <div class="c-newspaper__col">2</div>
  <div class="c-newspaper__col">3</div>
</div>

I added numbers for illustrating how every structure column might be reordered on totally different viewport sizes.

CSS grid sounds excellent for the above, proper?

First, we have to arrange the grid for all sizes.

.c-newspaper {
  show: grid;
  grid-template-columns: 1fr;
  hole: 1rem;
}

@media (min-width: 550px) {
  .c-newspaper {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

@media (min-width: 880px) {
  .c-newspaper {
    grid-template-columns: 1fr 2fr 1fr;
  }
}

A couple of issues to remember:

  • Initially, the grid has just one column. I used CSS grid to get the good thing about the hole property for spacing.
  • When the viewport width is 550px or bigger, the grid may have 3 columns. The identical occurs on the bigger viewport 880px, however the second column is double the dimensions of its sibling columns.

The vox.com kinds for the columns are constructed with the order property to reposition the columns on totally different sizes.

@media (min-width: 880px) {
  .c-newspaper__column:first-child {
    order: 1;
  }

  .c-newspaper__column:last-child {
    order: 3;
  }
}

With CSS grid, the above isn’t wanted in any respect as we are able to reorder the structure by positioning a component on any grid strains we would like.

Let’s discover tips on how to place the structure columns with CSS grid.

The medium viewport dimension

We have to place the columns as per the viewport width. For the medium dimension:

  • The primary column is positioned from line 2 to line 4.
  • The second column is positioned from line 1 to line 2.
  • The third column is positioned from line 1 to line 4 (spanning the complete width).
@media (min-width: 550px) {
  .c-newspaper {
    grid-template-columns: 1fr 1fr 1fr;
  }

  .c-newspaper__col:first-child {
    grid-column: 2/4;
  }

  .c-newspaper__col:nth-child(2) {
    grid-column: 1/2;
    grid-row: 1;
  }

  .c-newspaper__col:last-child {
    show: flex;
    grid-column: 1/4;
  }
}

The big viewport dimension

And for the massive dimension, do not forget that the second column is now 2fr, so it must double the dimensions of the aspect column.

  • The primary column is positioned from line 2 to line 3.
  • The second line stays inside the similar placement.
  • The final column is positioned from line 3 to line 4.
@media (min-width: 880px) {
  .c-newspaper {
    grid-template-columns: 1fr 2fr 1fr;
  }

  .c-newspaper__col:first-child {
    grid-column: 2/3;
  }

  .c-newspaper__col:last-child {
    grid-column: 3/4;
  }
}

A visible demo

Now that now we have a working grid, we are able to begin serious about the interior parts and tips on how to construct them.

Card element

That is the core focus of this text, the cardboard element. I compiled a visible of all of the variations now we have:

All of these can reside inside the featured part however with a special design variation for every card.

Let’s take the default card for instance:

In vox.com HTML, the cardboard has the next CSS courses:

<div
  class="c-entry-box--compact c-entry-box--compact--article c-entry-box--compact--hero c-entry-box--compact--2"
></div>

That could be a lengthy listing of CSS courses, and the category identify itself is prolonged, too.

A have a look at a couple of particulars on Vox structure

Card thumbnail

The cardboard element is in-built a method that makes use of lots of variation courses. For instance, right here is how the thumbnail is hidden within the plain card:

.c-entry-box--compact--7 .c-entry-box--compact__image-wrapper {
  show: none;
}

A customized variation class is used for each single card within the featured part. In whole, the CSS appears to be like like this:

That’s an excessive amount of, I believe.

Card title dimension

The title dimension for the default card is 20px and 16px for the plain card (and not using a thumbnail).

Right here is how that’s dealt with on vox.com:

@media (min-width: 880px)
    .c-newspaper .c-entry-box--compact__title {
        font-size: .9em;
    }
}

The .c-newspaper is the principle component that incorporates all of the playing cards, so utilizing it like that to tag the title component doesn’t look proper to me. What if that must be utilized in one other container that doesn’t have the category .c-newsppaper?

Separator

There’s a line separate between playing cards. It’s being dealt with within the CSS like this:

.c-newspaper .c-entry-box--compact {
  border-bottom: 1px stable #d1d1d1;
}

Two issues that don’t look good to me right here:

  • Utilizing .c-newspaper component to pick the cardboard.
  • Including the separator on to the cardboard itself. This can be a conditional type that isn’t associated to the cardboard.

Rethinking the cardboard with trendy CSS

The primary motivation for this text is the cardboard element. Once I began serious about it, I bought the thought to make use of some or all of those options:

  • CSS grid
  • aspect-ratio
  • textual content wrap balancing
  • CSS :has
  • Fluid sizing and spacing
  • Measurement container queries
  • Fashion container queries

I already explored utilizing CSS grid for the principle structure. Here’s what the HTML markup appears to be like like:

<div class="c-newspaper">
  <div class="c-newspaper__col">
    <div class="c-newspaper__item">
      <article class="c-card">
        
      </article>
    </div>
    <div class="c-newspaper__item"></div>
    <div class="c-newspaper__item"></div>
  </div>
  
</div>

The cardboard element lives inside the .c-newspaper__item, which acts as the cardboard container.

Usually talking, I prefer to wrap the element in an summary container. That is helpful for:

  • Including borders
  • Controlling the spacing
  • Works nicely for dimension container queries

Card meta font household

When the cardboard element is inside the featured part, the font household of the writer’s identify is totally different. To do this, we are able to verify if the next container question works, and if sure, the font might be utilized.

@container foremost (min-width: 1px) {
  .c-card__meta {
    font-family: "Playfair Show", serif;
  }
}

Default card type

We have to set a default card type that we are able to type. On this case, each the horizontal and stacked kinds are used equally, however I’ll assume that the stacked card is used extra, only for the sake of the article.

<article class="c-card">
  <div class="c-card__thumb"></div>
  <div class="c-card__content">
    <h3 class="c-card__title"></h3>
    <p class="c-card__tease"></p>
    <p class="c-card__meta"></p>
  </div>
</article>

Cool! Let’s from there for the remainder of the variations.

Horizontal type

The cardboard will flip to the horizontal type when its container is bigger than 300px and the CSS variable --horizontal: true has been set on the container.

<div class="c-newspaper__item" type="--horizontal: true;">
  <article class="c-card"></article>
</div>
.c-newspaper__item {
  container-type: inline-size;
  container-name: card;
}

@container card (min-width: 300px) and type(--horizontal: true) {
  .c-card {
    show: flex;
    hole: 1rem;
  }
}

Discover that I mixed a dimension and a method container question. The scale question works based mostly on the container width. Whereas the type question works by checking if the CSS variable is there.

We even have the identical variation however with the cardboard thumbnail positioned being flipped. We will try this by way of the order property.

To question that, we have to add the variable --flipped: true.

<div
  class="c-newspaper__item"
  type="--horizontal: true; 
           --flipped: true"
></div>

At first, I attempted the next CSS but it surely didn’t work as anticipated. It’s not attainable to merge two container queries for various containers. In my case, the containers are foremost and card.


@container foremost (min-width: 550px) and card type(--flipped: true) {
}

After studying the spec, I seen the next:

Whereas it’s not attainable to question a number of containers in a single container question, that may be achieved by nesting a number of queries:

I nested the type question inside one other container question. In plain phrases, that’s like saying:

When the container foremost width is the same as or bigger than 550px and the CSS variable —flipped is about on the playing cards container, apply the next CSS.

.wrapper {
  max-width: 1120px;
  margin: 1rem auto;
  padding-inline: 1rem;
  container-name: foremost;
  container-type: inline-size;
}

@container foremost (min-width: 550px) {
  @container card type(--flipped: true) {
    .c-card__thumb {
      order: 2;
    }
  }
}

To be taught extra about container queries, listed below are a couple of write-ups on the subject:

Card thumbnail side ratio

The present method of implementing ting the cardboard thumbnail doesn’t account for when there may be a picture with a special side ratio. We will use the CSS aspect-ratio property to pressure the cardboard thumb to have the identical side ratio.

Let’s assume that I added a big picture that has a special side ratio. We’ll find yourself with one thing like this:

To keep away from that, we are able to outline a side ratio:

.c-card__thumb img {
  aspect-ratio: 5/3;
  object-fit: cowl;
}

In case you are to be taught extra about side ratio, I wrote an article about that.

Card horizontal type

On vox.com, the horizontal card type was in-built a method that feels a bit pointless.


.c-entry-box--compact__image-wrapper {
  width: 30%;
}

.c-entry-box--compact__body {
  flex-grow: 1;
  width: 70%;
}

Why is that? I assume that’s to keep away from having such a UI conduct:

Discover that I discussed “UI conduct”, not a bug. The above is a default conduct for flexbox. We have to pressure the picture to have a hard and fast and constant dimension.

.c-entry-box--compact__image-wrapper {
  flex: 0 0 30%;
}

.c-entry-box--compact__body {
  flex-grow: 1;
}

We will repair that by merely utilizing the flex property. No want to make use of the width.

The featured card is displayed horizontally when the container width is small and can change to the stacked kinds on bigger sizes. On this case, the thumbnail turns into bigger and takes 50% of the width.

Here’s a comparability between a default horizontal type and the featured one.

When the container width turns into bigger, the cardboard type will turn into stacked.

To implement that, I used the --featured variable on the cardboard’s container.

<div class="c-newspaper__item" type="--featured: true;"></div>

Firstly, I added the horizontal type as default.

  • Added flex to activate the horizontal design.
  • The cardboard thumb takes 50% of the accessible width.
  • Modified the font household to a serif font and a bigger dimension, as per the design.
@container type(--featured: true) {
  .c-card {
    show: flex;
    hole: 1rem;
  }

  .c-card__thumb {
    flex: 0 0 50%;
  }

  .c-card__tease {
    font-family: "Playfair Show", serif;
    font-size: 19px;
  }
}

When the container dimension will get bigger, the browser will apply the stacked styling to the cardboard.

@container foremost (min-width: 550px) {
  @container card type(--featured: true) {
    .c-card {
      flex-direction: column;
      hole: 0;
    }

    .c-card__title {
      font-size: calc(1rem + 2.5cqw);
    }

    .c-card__content {
      text-align: heart;
    }

    .c-card__thumb {
      flex: preliminary;
    }
  }
}

Plain card

On this variation, the font dimension will get smaller. That occurs when the picture is hidden. At first, I considered utilizing CSS :has to verify if the cardboard thumb is displayed or not.

In vox.com, the cardboard thumb is hidden by way of CSS, so it’s not attainable to make use of :has as it will likely be legitimate even when the thumb is hidden.

<article class="c-card">
  <div class="c-card__thumb"></div>
  <div class="c-card__content"></div>
</article>
.c-card__thumb {
  show: none;
}


.c-card:has(.c-card__thumb) .c-card__title {
  font-size: 19px;
}

If the picture could be conditionally added by way of Javascript, then we are able to use :has. In any other case, I’ll default to a method question.

@container foremost (min-width: 550px) {
  @container card type(--compact: 2) {
    .c-card__title {
      font-size: 19px;
    }
  }
}

Spacing and separators

The present method in vox.com to deal with the spacing is by including padding on to the cardboard. I don’t want that. The cardboard kinds shouldn’t rely upon the place it lives. The spacing ought to be added to the cardboard’s wrapper as an alternative.

To make issues simpler, I added a CSS variable --gap to every column.

.c-newspaper__col {
  --gap: 20px;
  show: flex;
  flex-direction: column;
}

I added a margin-block to every card wrapper.

  • On small viewports, there aren’t any separators.
  • When the dimensions is medium, there are separates for the primary two columns, and one border for the final one.

The CSS property margin-block is a logical property which means each margin-top and margin-bottom.

@media (min-width: 550px) {
  .c-newspaper__item:not(:last-child):after {
    content material: "";
    show: block;
    top: 1px;
    background-color: lightgrey;
    margin-block: var(--gap);
  }

  .c-newspaper__col:last-child {
    border-top: 1px stable lightgrey;
    padding-top: var(--gap);
  }
}

@media (min-width: 880px) {
  .c-newspaper__col:last-child {
    padding-top: 0;
    border-top: 0;
  }

  
  .c-newspaper__col:last-child
    .c-newspaper__item:not(:last-child):after {
    content material: "";
    show: block;
    top: 1px;
    background-color: lightgrey;
    margin-block: var(--gap);
  }
}

You is likely to be considering, why not use hole? The reason being that I received’t use trendy CSS for the sake of utilizing it. It’s not helpful right here as a result of:

  • it solely works for one a part of the spacing, and I’ve to make use of margin-top with it.
  • I want there’s a native CSS method so as to add borders, similar to the CSS property column-rule in CSS columns.

Container models

One factor that I like about container queries is the flexibility to make use of container models. They’re like viewport models however for a selected container. Isn’t that highly effective?

@container foremost (min-width: 550px) {
  @container card type(--featured: true) {
    .c-card__title {
      font-size: clamp(1rem, 6cqw, 2rem);
    }
  }
}

Study extra about container question models.

Textual content balancing

Not too long ago, I wrote concerning the new CSS characteristic text-wrap: stability, which remains to be in Chrome Canary solely on the time of writing this text.

Within the structure that I’m constructing, we are able to leverage that for all of the textual content content material. It may well make the structure look extra organized.

Study extra about textual content wrap balancing.

Closing demo

You possibly can play right here with the ultimate demo. I like to recommend checking that on Chrome Canary.

Disclaimer: the design isn’t similar to Vox, this demo focuses extra on the structure and parts implementation.

Outro

One of many issues that pressure me to be taught and discover CSS is the curiosity to see how folks construct issues. I get pleasure from that course of and be taught quite a bit whereas doing so. I hope you discovered the article useful.

Do you could have a query or suggestions? Please be at liberty to ping me on Twitter @shadeed9.



RELATED ARTICLES

Most Popular

Recent Comments