23
Author: Ahmad Shadeed
Translator: Front-end Xiaozhi Source: isadeed

A new series is out: Vue2 and Vue3 Tips Booklet

Wechat search [Great Relocation to the World], I will share with you the front-end industry trends, learning methods, etc. as soon as possible.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.

Many times we wish there was a way to avoid a certain CSS issue or behavior from happening. We know that web content is dynamic and things on a web page can change, increasing the likelihood of CSS issues or strange behavior.

Defensive CSS is a collection of snippets that help me write protected CSS. In other words, there will be more bugs in the future.

1. Flexbox Package

CSS flexbox is one of the most useful CSS layout features out there. Add display: flex to a wrapper to sort the children next to each other.

The problem is that those subitems are not wrapped into a new row by default when there is not enough space. We need to use flex-wrap: wrap to change this behavior.

Below is a typical example.

 .options-list {
    display: flex;
}

Horizontal scrolling occurs when there is less space. This should be expected and is not actually a "problem".

 .options-list {
    display: flex;
    flex-wrap: wrap;
}

When using flexbox , the general rule of thumb is to allow wraps unless you want a rolling wrap. That's another story, but try to use flex-wrap to avoid unexpected layout behavior (in our case, horizontal scrolling).

2. Spacing

We developers need to consider different content lengths. This means, spacing should be added to the component even if it doesn't appear to be needed.

In this example, we have a section title and an action button on the right. For now, it looks fine. But what would happen if the title were longer?

Notice how the text is too close to the button? Here, you might consider multiple line wrapping, but for now, let's focus on spacing.

If the title has spaces and text is truncated, we don't see such a problem.

 .section__title {
    margin-right: 1rem;
}

3. Long Content

When building layouts, it's important to take long content into account. As you saw earlier, chapter titles are truncated when they are too long. This is optional, but for some UIs it's important to take this into account.

To me, this is a defensive CSS approach. It's good to fix the "problem" before it actually happens.

Here's a list of names that look perfect right now

However, since this is user-generated content, we need to be careful how we defend the layout in case some content is too long. Please see the image below:

In this layout, consistency is very important. To achieve this, we can simply truncate the name using text-overflow and its friends.

4. Prevent images from being stretched or compressed

In the case where the image aspect ratio cannot be controlled, if the image uploaded by the user does not match the aspect ratio, it is best to consider and provide a solution in advance.

In the example below, we have a card component with a photo. It looks good.

When the user uploads an image of a different size, it will be stretched. This is not a good thing. See how the image is stretched!

The easiest fix is to use CSS object-fit .

 .card__thumb {
    object-fit: cover;
}

On a project level, I tend to add object-fit for all images to avoid unexpected results.

5. Lock Scroll Links

Have you ever opened a modal and started scrolling, then when you reach the end and continue scrolling, the content (body element) below the modal scrolls? This is called a rolling chain.

By default, when touching the top or bottom of the page (or other scrollable area), mobile browsers tend to provide a "bottom out" effect or even a page refresh. You may also find that when a dialog has scrollable content, once you scroll to the borders of the dialog, the page content below the dialog also starts to scroll - this is called a "scroll chain". .

Over the past few years, there have been some hacks to achieve this, but now, we just use CSS, thanks to the overscroll-behavior CSS property.

In the image below, you can see the default scroll link behavior.

To avoid this in advance, we can add it to any component that needs scrolling (eg: chat component, mobile menu...etc). The nice thing about this property is that it doesn't have an effect until there is scrolling.

 .modal__content {
    overscroll-behavior-y: contain;
    overflow-y: auto;
}

6. CSS Variable Fallback

CSS variables are used more and more in web design. We can apply a way to use CSS variable values in a way that doesn't break the experience in case they are null for some reason.

Especially useful when entering the value of CSS variables via JS. Below is an example:

 .message__bubble {
    max-width: calc(100% - var(--actions-width));
}

The variable --actions-width is used in the calc() function and its value comes from JS. Suppose JS fails for some reason, what happens? max-width will be calculated as zero.

We can avoid this earlier by adding a fallback value to var() .

 .message__bubble {
    max-width: calc(100% - var(--actions-width, 70px));
}

This way, if the variable is not defined, the fallback (70px) is used. This approach can be used in situations where variables may fail.

7. Use a fixed width or height

One of the common things that breaks a layout is using a fixed width or height for an element that has content of varying lengths.

fixed height

I often see the main content section has a fixed height and the content is larger than this height, which leads to broken layout. As follows:

 .main {
    height: 350px;
}

To avoid this, use min-height instead of height :

fixed width

Have you ever seen a button with its label too close to the left and right edges? This is due to the use of a fixed width.

 .button {
    width: 100px;
}

If the button's label is larger than 100px , it will be close to the edge. If it's too long, the text will leak out. this is not good!

To fix this, we can simply replace ---e1cd62cabdd426001a873a4974c3ee8d min-width with width .

 .button {
    min-width: 100px;
}

8. Forget the background-Repeat

Many times, when using a large image as a background, we tend to forget to consider how the design will look when viewed on a large screen. The background will repeat by default.

This is mostly not seen on laptop screens, but is common on larger screens.

To avoid this behavior in advance, make sure to use reset background-repeat .

 .hero {
    background-image: url('..');
    background-repeat: no-repeat;
}

9. Vertical Media Queries

Sometimes, we're tempted to build a component and test it only by adjusting the width of the browser. Testing against browser height can reveal some interesting issues.

Here's an example that I've seen multiple times. We have a component with primary and secondary links. Secondary links should be at the very bottom of the narration section.

Consider the following example. The primary and secondary navigation looks fine. In the example I saw, the developer added position: sticky to the secondary navigation so that it would stick to the bottom.

However, if the height of the browser is small, the bug comes. Notice how the two navigations overlap.

By using CSS vertical media queries, we can avoid this problem.

 @media (min-height: 600px) {
    .aside__secondary {
        position: sticky;
        bottom: 0;
    }
}

This way, the secondary nav will be stuck to the bottom only if the viewport height is greater than or equal to 600px . Much better, right?

There are probably better ways to achieve this behavior (like using margin-auto ), but focus on vertical queries for this example.

10. Use justify-content:space-between

In a container of flex we might use justify-content to have some spacing between subitems. The layout will look fine if there is a certain number of sub-items. However, when they increase or decrease, the layout will look weird.

Consider the following example:

We have a flex container with four items. The spacing between each item is not gap or margin , it exists because the container has justify-content: space-between .

 .wrapper {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
}

When the number of items is less than 4, the following happens:

This is not a good thing. There are different solutions for this:

  • margin
  • flexbox gap (use with caution)
  • padding (applies to each child element's parent element)
  • Add empty elements as spacers.

For simplicity, I use gap .

 .wrapper {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

11. Text on pictures

When placing text over an image, you must take into account the fact that the image fails to load. What the text will look like. Below is an example:

The text appears to be readable, but when the image fails to load it becomes poorly readable.

We solved this easily by adding a background color to the <img> element. This background is only shown if the image fails to load.

12. Be careful with fixed values in CSS grids

Suppose we have a grid containing aside and main . CSS looks like this:

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

This can be problematic on small viewport sizes due to lack of space. To avoid problems like this, be sure to use media queries when using the above CSS grid.

 @media (min-width: 600px) {
    .wrapper {
        display: grid;
        grid-template-columns: 250px 1fr;
        gap: 1rem;
    }
}

13. Show scrollbars only when needed

We can control showing scrollbars or not just in case of long content. Nonetheless, it is strongly recommended to use auto as the value for overflow . Consider the following example:

Note that there is a scrollbar visible even if the content is short. This is not good for a user interface. As a user, it's confusing to see scrollbars when you don't need them.

 .element {
    overflow-y: auto;
}

With overflow-y: auto , the scrollbar is only visible when the content is long. Otherwise, it is not displayed.

14. Scrollbar Gutter

Another thing to do with scrolling is Scrollbar Gutter . Taking the previous example as an example, adding a scrollbar will cause the layout to shift when the content gets longer. The layout movement happens because a space is reserved for the scroll bar.

The Scrollbar Gutter is the space between the inner border edge and the outer padding edge. For classic scrollbars, the size of the Scrollbar Gutter is the same as the width of the scrollbar. These scroll bars are usually opaque and take up some space from adjacent content.

Please see the image below:

Notice how it shifts as the content gets longer due to the scrollbar being shown. We can avoid this behavior by using the scrollbar-gutter attribute.

 .element {
    scrollbar-gutter: stable;
}

15. Minimum Content Size in CSS Flexbox

If the text elements or images in a flex item are larger or longer than the item itself, the browser will not shrink them. This is the default behavior of Flexbox. Consider the following example:

 .card {
    display: flex;
}

When the title has a very long word, it is not wrapped into a new line.

Even if we use overflow-wrap: break-word , it won't work.

 .card__title {
    overflow-wrap: break-word;
}

To change this default behavior, we need to set the flex project's min-width to 0 . This is because the default value of ---f2d6f877c5a1d79f58479cb57daeb648 min-width is auto and overflow occurs.

 .card__title {
    overflow-wrap: break-word;
    min-width: 0;
}

The same applies to the flex-direction:column layout, and the corresponding use min-height: 0 .

16. Minimum Content Size in CSS Grid

Similar to flexbox, CSS grid has a default minimum content size for its children, which is auto . This means that if an element is larger than the grid item, it will overflow.

In the above example, we have a carousel in the main section.

 <div class="wrapper">
    <main>
        <section class="carousel"></section>
    </main>
    <aside></aside>
</div>
 @media (min-width: 1020px) {
    .wrapper {
        display: grid;
        grid-template-columns: 1fr 248px;
        grid-gap: 40px;
    }
}

.carousel {
    display: flex;
    overflow-x: auto;
}

Since carousel is a flex layout, when the content exceeds, it will not wrap by default, so horizontal scrolling will occur.

To solve this problem, we have three different solutions:

  • Use minmax()
  • Apply min-width to grid item
  • Add overflow: hidden to the network

As a defensive CSS mechanism, I would choose the first one, which is to use the minmax() function.

 @media (min-width: 1020px) {
    .wrapper {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 248px;
        grid-gap: 40px;
    }
}

  1. Auto Fit Vs Auto Fill

When using the CSS Grid minmax() function, it is important to decide whether to use the auto-fit or auto-fill keyword. Improper use can lead to unexpected results.

When using the minmax() function, the auto-fit keyword will expand the grid items to fill the available space. And auto-fill will preserve the available space without changing the width of the grid items.

That said, using auto-fit may cause grid items to be too wide, especially when they are smaller than expected. Consider the following example.


The bugs that may exist in editing cannot be known in real time. In order to solve these bugs afterwards, a lot of time is spent on log debugging. By the way, here is a useful bug monitoring tool , Fundebug .

Forgive: https://ishadeed.com/article/defensive-css/

comminicate

If you have dreams and dry goods, you can search for [Great Move to the World] on WeChat and pay attention to this Shawanzhi who is still washing dishes in the early hours of the morning.

This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.


王大冶
68.1k 声望105k 粉丝