Thursday, April 25, 2024
HomeCSSRebuilding a featured information part with fashionable CSS: Vox information

Rebuilding a featured information part with fashionable CSS: Vox information


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

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

Desk of contents

Analyzing the part

Within the largest viewport, we have now 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 we have now an concept in regards to the columns, let’s check out the parts inside them.

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

Adjustments from the big to medium

  • Featured part: virtually the identical, however with a special font dimension that’s altering primarily based on the viewport width.
  • Blue part: the font dimension of every card title received 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 fashion with the thumbnail proven for each.
  • 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, we have now 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 function as this feels extra like a CSS grid use case. I imagine the Vox crew 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 answerable for the next:

  • Setting the width of the column. Utilizing width property for that works positive, however we are able to additionally use the flex property.
  • Including padding on the left and proper sides is an outdated strategy to introduce a spot between columns. Now we have now 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">
    <!-- Featured column -->
    <div class="c-newspaper__col">1</div>
    
    <!-- Different columns -->
    <div class="c-newspaper__col">2</div>
    <div class="c-newspaper__col">3</div>
</div>

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

CSS grid sounds good 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;
    }
}

Just a few issues to remember:

  • Initially, the grid has just one column. I used CSS grid to get the advantage of the hole property for spacing.
  • When the viewport width is 550px or bigger, the grid can 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 types 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 easy methods 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 total 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 massive viewport dimension

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

  • The primary column is positioned from line 2 to line 3.
  • The second line stays throughout the identical 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 we have now a working grid, we are able to begin interested by the inside parts and easy methods to construct them.

Card part

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

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

Let’s take the default card for example:

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

<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 lessons, and the category title itself is prolonged, too.

A have a look at just a few particulars on Vox structure

Card thumbnail

The cardboard part is inbuilt a approach that makes use of plenty of variation lessons. 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 feel.

Card title dimension

The title dimension for the default card is 20px and 16px for the plain card (with no 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 ingredient that accommodates all of the playing cards, so utilizing it like that to tag the title ingredient 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 strong #d1d1d1;
}

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

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

Rethinking the cardboard with fashionable CSS

The primary motivation for this text is the cardboard part. Once I began interested by it, I received the concept 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
  • Type 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">
                <!-- Card part -->
            </article>
        </div>
        <div class="c-newspaper__item"></div>
        <div class="c-newspaper__item"></div>
    </div>
    <!-- Different columns -->
</div>

The cardboard part lives throughout the .c-newspaper__item, which acts as the cardboard container.

Typically talking, I wish to wrap the part in an summary container. That is helpful for:

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

Card meta font household

When the cardboard part is throughout the featured part, the font household of the creator’s title is totally different. To do this, we are able to examine if the next container question works, and if sure, the font shall be utilized.

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

Default card fashion

We have to set a default card fashion that we are able to fashion. On this case, each the horizontal and stacked types 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 fashion

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

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

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

Discover that I mixed a dimension and a method container question. The dimensions question works primarily based on the container width. Whereas the fashion 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 do this through the order property.

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

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

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

/* That did not work */
@container important (min-width: 550px) and card fashion(--flipped: true) { }

After studying the spec, I seen the next:

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

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

When the container important width is the same as or bigger than 550px and the CSS variable –flipped is ready on the playing cards container, apply the next CSS.

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

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

To be taught extra about container queries, listed here are just a few write-ups on the subject:

Card thumbnail facet ratio

The present approach of implementing ting the cardboard thumbnail doesn’t account for when there’s a picture with a special facet ratio. We will use the CSS aspect-ratio property to power the cardboard thumb to have the identical facet ratio.

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

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

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

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

Card horizontal fashion

On vox.com, the horizontal card fashion was inbuilt a approach that feels a bit pointless.

/* CSS from vox.com */
.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 power 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 types 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 fashion and the featured one.

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

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

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

Firstly, I added the horizontal fashion as default.

  • Added flex to activate the horizontal design.
  • The cardboard thumb takes 50% of the obtainable width.
  • Modified the font household to a serif font and a bigger dimension, as per the design.
@container fashion(--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 important (min-width: 550px) {
    @container card fashion(--featured: true) {
        .c-card {
            flex-direction: column;
            hole: 0;
        }

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

        .c-card__content {
            text-align: middle;
        }
        
        .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 thought of utilizing CSS :has to examine if the cardboard thumb is displayed or not.

In vox.com, the cardboard thumb is hidden through CSS, so it’s not potential to make use of :has as will probably 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;
}

/* This may at all times work. */
.c-card:has(.c-card__thumb) .c-card__title {
    font-size: 19px;
}

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

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

Spacing and separators

The present approach in vox.com to deal with the spacing is by including padding on to the cardboard. I don’t desire that. The cardboard types shouldn’t rely on the place it lives. The spacing must be added to the cardboard’s wrapper as a substitute.

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 strong lightgrey;
    padding-top: var(--gap);
  }
}

@media (min-width: 880px) {
  .c-newspaper__col:last-child {
    padding-top: 0;
    border-top: 0;
  }
  
  /* Add separators to the final column */
  .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 could be pondering, why not use hole? The reason being that I received’t use fashionable 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 approach so as to add borders, similar to the CSS property column-rule in CSS columns.

Container items

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

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

Study extra about container question items.

Textual content balancing

Not too long ago, I wrote in regards to the new CSS function text-wrap: steadiness, 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 could make the structure look extra organized.

Study extra about textual content wrap balancing.

Closing demo

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

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

Outro

One of many issues that power me to be taught and discover CSS is the curiosity to see how other people construct issues. I get pleasure from that course of and be taught rather a lot whereas doing so. I hope you discovered the article useful.

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



RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments