Implementing a consistent CSS structure for various media sizes

Utilizing CSS grid and Sass, I implement varying grid layouts for different screen sizes (phone, tablet, desktop). However, on certain pages, I desire the same layouts at slightly larger or smaller screens than others.

Is there a way to achieve this without duplicating styles excessively? My current solution (shown below) functions, but results in repetitive styling.

To elaborate:

I have 3 distinct grids selected according to screen size.

.hero {
    &__container {
        grid-template-areas:
            "header"
            "image"
            "text";
        }
        @media min-width: 1000px {
            grid-template-areas:
                "header header header"
                "text   ...     image"
                "text   ...     image";
            }
            // additional definitions for this screen size
        }
        @media min-width: 1300px {
            grid-template-areas:
                "header header image"
                "text   ...    image"
                "text   ...    image";
            }
            // other definitions for this size
        }
    }

  &__header {
    grid-area: header;
    font-size: 2.5rem;
    
    @media min-width: 1000px {
        font-size: 2.8rem;
    }
    @media min-width: 1300px {
        font-size: 3.2rem;
    }
  }
  ...
}

These are utilized across approximately 20 similar web pages.

<div class="page_a">
    <div class="hero">
        <div class="hero__container">
            <div class="hero__header">...</div>
            <div class="hero__text">...</div>
            <div class="hero__image">...</div>
        </div>
    </div>
</div>

The layout remains consistent, however, I wish to transition to different layouts at varying breakpoints based on content specifics like header text length, image size, importance, etc.

What I aim to accomplish is depicted as follows:

.page_a {
    .hero {
        // retain default settings, no alterations
    }
}

.page_c {
    .hero {
        // longer header requires bigger screen for largest layout switch 
        // specify that the 1300px layout should be used from 1500px
    }
}

The sole workaround I achieved was merely redefining all the grids at each potential breakpoint (default + custom ones), leading to excessive repetition in the code:

.page_c {
    .hero {
        // utilize 1000px layout also for 1300px - whole process needs to be repeated
        @media min-width: 1300px {
            grid-template-areas:
                "header header header"
                "text   ...     image"
                "text   ...     image";
            }
            // additional definitions for this size
        }
        // use 1300px layout for 1500px - entire set of rules has to be reiterated
        @media min-width: 1500px {
            grid-template-areas:
                "header header image"
                "text   ...    image"
                "text   ...    image";
            }
            // other specifications for this size
        }
    }
}

This implies that whenever a layout adjustment is made, changes must be applied throughout all instances where it is used at various sizes.

Answer №1

Consider using SASS or SCSS along with a @mixin to solve your issue. I personally prefer SCSS, but you can also use SASS.

Understanding the @mixin

According to the official SASS documentation:

Mixins enable you to define styles that are reusable throughout your stylesheet.

To utilize a @mixin, first define it and then call it in your code using an @include. Each @mixin should have a distinct name. For instance, create a @mixin layout_600 and employ it with an @include layout_600.

There are two key considerations when working with @mixin:

  1. Define a @mixin before utilizing it with an @include. Otherwise, SCSS will attempt to call something undefined as it's declared later in your stylesheet.
  2. Declare a @mixin outside of your nested code (preferably at the top of your stylesheet). If you define a @mixin within nested code, you won't be able to reference it later for modifying default styles. To understand this concept better, let me show you the right way versus the wrong way.

Correct Approach:

@mixin layout_600 {
    font-size: 3rem;
    color: blue;
    font-weight: 700;
}

.hero {
    &__header {
        @media (min-width: 600px) {
            @include layout_600;
        }
    }
}

.page_b {
    .hero {
        // Using the 600px layout for 1000px width as well
        &__header {
            @media (min-width: 1000px) {
                // This works successfully
                @include layout_600;
            }
        }
    }
}

Incorrect Approach:

.hero {
    &__header {
        @media (min-width: 600px) {
            @mixin layout_600 {
                font-size: 3rem;
                color: blue;
                font-weight: 700;
            }
        }
    }
}

.page_b {
    .hero {
        // Using the 600px layout for the 1000px as well
        &__header {
            @media (min-width: 1000px) {
                // This won't work
                @include layout_600;
            }
        }
    }
}

For each desired layout (e.g., 600px), create a @mixin. You only need to define it once per layout, but you can invoke a particular @mixin multiple times. This has several advantages:

  • No need to rewrite your code, simply call the specific @mixin with @include whenever needed.
  • If style modifications are required, update the @mixin once. The changes will reflect across all references to that @mixin.

Demonstration Example

Prior to Default Style Alteration

I defined three @mixins like so:

  • for window width < 600px,
  • for 600px < window width < 1000px and
  • for window width > 1000px.

https://i.stack.imgur.com/dC7Qw.png

The font-size and color vary based on different window widths. Font size increases and color transitions from black to blue to red as window width expands. Additionally, there's a div in the top right corner displaying current window width.

Post Default Style Modification

I opted to utilize the 600px layout (@mixin layout_600) for page_b even at 1000px. Achieving this is simple by calling @mixin layout_600 via @include layout_600 as shown below:

.page_b {
    .hero {
        // Applying 600px layout for 1000px width as well
        &__header {
            @media (min-width: 1000px) {
                @include layout_600;
            }
        }
    }
}

https://i.stack.imgur.com/vmTWf.png

In the scenario where window width actually reaches 1000px, the styling for page_b mirrors that of 600px width (smaller font and blue color).

Customizing a @mixin

You can also customize a @mixin if necessary. For example, I utilized the 600px layout (@mixin layout_600) but altered the color from red to green as illustrated below:

.page_b {
    .hero {
        // Applying 600px layout for 1000px width as well
        &__header {
            @media (min-width: 1000px) {
                @include layout_600;
                color: green; // Customizing the mixin
            }
        }
    }
}

https://i.stack.imgur.com/NkYdf.png

As evident, the color should've been blue (as dictated by @mixin layout_600), but it appears green instead.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Assigning a new classification to the primary object in the evolving array of objects

I'm working with an element that loops through all the objects using v-for and has a CSS class named top-class{}... I need to dynamically add the top-class to the first object (object[0]) and update it based on changes, removing the old top-class in t ...

Moving a popup div along with a marker in Leaflet can be achieved by using the set

After creating a map using leaflet and adding markers to different locations, I implemented code that displays a popup div with a message when a marker is clicked. Here is the code snippet: markers.on("click", function(d) { div.html("This is Some info ...

Creating a Dynamic Login Panel Using HTML, CSS, and Jquery

Designing a dynamic sliding login panel utilizing Html, CSS, and jquery alongside various plugins. Check it out here: http://24.125.42.135/ When activated, the bar smoothly pushes down the content (click on the login option at the top right corner). This ...

Vanished were the empty voids within our

It seems that the spaces between words have mysteriously vanished in a font I am currently using. Take a look at this website: I am utilizing a slightly modified Twitter Bootstrap with Google Web fonts, and the font causing the issue is Oswald from Googl ...

Hovering over the Instagram icon will reveal a stunning visual effect

I am looking to change the appearance of my Instagram icon when hovering over it. I want the background to turn white and the icon to become colored. Here is my code snippet from Footer.js : <a href="https://www.instagram. ...

Is there a way to trigger the opening of a new file or page when a CSS animation comes to an end?

Is there a way to delay the loading of a function or page until after an animation has finished running in JavaScript, HTML, and CSS only? For instance, I'd like to run an animation first and then have a different website or content load afterwards fo ...

Using scale transformations to animate SVG group elements

I am currently experimenting with an SVG example where I hover over specific elements to expand or scale them. However, I seem to have made a mistake somewhere or missed something important. Can someone offer me assistance? View the demo on JSFiddle here ...

Adjust the color of the navbar only after a user scrolls, with a slight delay rather than

My code changes the navbar colors when I scroll (200ms). However, I would like the changes to occur when I am slightly above the next section, not immediately. In other words, what adjustments should I make to change the color in the next section and not ...

Unveiling the Magic: Enhancing Raphaeljs with Interactive Click Events on a Delicious Slice of the

I'm having trouble responding to a click event on each slice of a Raphael Pie Chart. I've tried implementing the code below, but it doesn't seem to be working. The code is just two lines, commented as "My Code", in the example from the offic ...

Stop the button from spanning the entire width of its container

Utilizing the Material UI button in my application with customizations as styled-components, I encountered an issue where setting the size="small" prop on the button caused it to only take up the width of the button text with some padding. This behavior pe ...

Is there a way to extract the text from the inner div of an element using nightwatch.js?

I'm attempting to retrieve the content of a cell within a table, with the following CSS structure: <div data-testid="cellvalue_row-1_col-0" class="Table-cellContent" xpath="1"><span data-testid="tableCellCon ...

Drupal 7 FlexSlider - alignment issue with image placement

I am encountering an issue with the Flexslider module on my Drupal 7 website. I have created a simple slider that displays 3 photos. I enabled touch screen functionality for the slider, and everything seems to be working fine except for one problem - all t ...

Modify radio button colors upon selection with a variety of colors

Looking to create Yes/No buttons that start with a default state of null and change color when pressed - green for yes, red for no. Check out this example code: <label class="formheading">Apparatus group is correct</label> <fieldset data-r ...

Transforming the hue of a radio-button

When it comes to the default CSS code for radio buttons, they appear gray when unselected and blue when selected: https://i.stack.imgur.com/hsazr.png However, I have a specific requirement for them to be black in both states. In order to achieve this, I ...

Tips on adjusting the text color of the material radio button

Looking for some assistance here. I'm working with a small piece of code that combines Material UI and Angular. I have a radio button group where the text color is not changing, despite setting the SCSS value to #262D34. <mat-radio-group aria-label ...

Adding an input field and icon at the center using ::after

Having trouble centering an input field with an icon after it in a div. I can center the input text easily using text-align:center, but struggling to center the icon added using ::before. The search text is centered, but not the icon How can I center bot ...

Text-color in the v-tooltip

Is there a way to change the text color of v-tooltips components without affecting the tooltip background color? I attempted to inspect the element, but the tooltip only appears on hover, making it impossible to inspect. Below is the code snippet: < ...

Tips on adjusting a position that shifts with changes in window size

Working on a website for my grandpa, I'm planning to include a small biker character that runs across the screen. When hovered over, he stops and advises "wear a helmet." The animation works well, but there's an issue with the positioning when th ...

Unable to implement the `omega/theme.css` file within the angular.json configuration

"styles": [ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", "node_modules/bootstrap/dist/css/bootstrap.min.css", "src/styles.css", "node_modules/primeicons/primeicons.css", ...

How to create a slideToggle effect for nested ul and li elements

Initially, everything was working fine until I put it through the W3C validator. After fixing the errors, now it's not functioning as expected. I have created a jsfiddle The setup involves nested ul elements being used as dropdowns, with headers tha ...