Saleh Mubashar – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Thu, 09 Feb 2023 15:03:59 +0000 en-US hourly 1 https://wordpress.org/?v=6.2.2 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 Saleh Mubashar – CSS-Tricks https://css-tricks.com 32 32 45537868 Moving Backgrounds https://css-tricks.com/moving-backgrounds/ https://css-tricks.com/moving-backgrounds/#comments Thu, 09 Feb 2023 15:03:55 +0000 https://css-tricks.com/?p=376723 We often think of background images as texture or something that provides contrast for legible content — in other words, not really content. If it was content, you’d probably reach for an <img> anyway, accessibility and whatnot.

But there are …


Moving Backgrounds originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
We often think of background images as texture or something that provides contrast for legible content — in other words, not really content. If it was content, you’d probably reach for an <img> anyway, accessibility and whatnot.

But there are times when the position or scale of a background image might sit somewhere between the poles of content and decoration. Context is king, right? If we change the background image’s position, it may convey a bit more context or experience.

How so? Let’s look at a few examples I’ve seen floating around.

As we get started, I’ll caution that there’s a fine line in these demos between images used for decoration and images used as content. The difference has accessibility implications where backgrounds are not announced to screen readers. If your image is really an image, then maybe consider an <img> tag with proper alt text. And while we’re talking accessibility, it’s a good idea to consider a user’s motion preference’s as well.

Show me more!

Chris Coyier has this neat little demo from several years back.

The demo is super practical in lots of ways because it’s a neat approach for displaying ads in content. You have the sales pitch and an enticing image to supplement it.

The big limitation for most ads, I’d wager, is the limited real estate. I don’t know if you’ve ever had to drop an ad onto a page, but I have and typically ask the advertiser for an image that meets exact pixel dimensions, so the asset fits the space.

But Chris’s demo alleviates the space issue. Hover the image and watch it both move and scale. The user actually gets more context for the product than they would have when the image was in its original position. That’s a win-win, right? The advertiser gets to create an eye-catching image without compromising context. Meanwhile, the user gets a little extra value from the newly revealed portions of the image.

If you peek at the demo’s markup, you’ll notice it’s pretty much what you’d expect. Here’s an abridged version:

<div class="ad-container">
  <a href="#" target="_blank" rel="noopener">
    <!-- Background image container  -->
    <div class="ad-image"></div>
  </a> 
  <div class="ad-content">
    <!-- Content -->
  </div>
</div>

We could probably quibble over the semantics a bit, but that’s not the point. We have a container with a linked-up <div> for the background image and another <div> to hold the content.

As far as styling goes, the important pieces are here:

.container {
  background-image: url("/path/to/some/image.png");
  background-repeat: no-repeat;
  background-position: 0 0;
  height: 400px;
  width: 350px;
}

Not bad, right? We give the container some dimensions and set a background image on it that doesn’t repeat and is positioned by its bottom-left edge.

The real trick is with JavaScript. We will use that to get the mouse position and the container’s offset, then convert that value to an appropriate scale to set the background-position. First, let’s listen for mouse movements on the .container element:

let container = document.querySelector(".container");
container.addEventListener("mousemove", function(e) {
    // Our function
  }
);

From here, we can use the container’s offsetX and offsetY properties. But we won’t use these values directly, as the value for the X coordinate is smaller than what we need, and the Y coordinate is larger. We will have to play around a bit to find a constant that we can use as a multiplier.

It’s a bit touch-and-feel, but I’ve found that 1.32 and 0.455 work perfectly for the X and Y coordinates, respectively. We multiply the offsets by those values, append a px unit on the result, then apply it to the background-position values.

let container = document.querySelector(".container");
container.addEventListener("mousemove", function(e) {
    container.style.backgroundPositionX = -e.offsetX * 1.32 + "px";
    container.style.backgroundPositionY = -e.offsetY * 0.455 + "px";
  }
);

Lastly, we can also reset the background positions back to the original if the user leaves the image container.

container.addEventListener("mouseleave", function() {
    container.style.backgroundPosition = "0px 0px";
  }
);

Since we’re on CSS-Tricks, I’ll offer that we could have done a much cheaper version of this with a little hover transition in vanilla CSS:

Paint a bigger picture

No doubt you’ve been to some online clothing store or whatever and encountered the ol’ zoom-on-hover feature.

This pattern has been around for what feels like forever (Dylan Winn-Brown shared his approach back in 2016), but that’s just a testament (I hope) to its usefulness. The user gets more context as they zoom in and get a better idea of a sweater’s stitching or what have you.

There’s two pieces to this: the container and the magnifier. The container is the only thing we need in the markup, as we’ll inject the magnifier element during the user’s interaction. So, behold our HTML!

<div class="container"></div>

​​In the CSS, we will create width and height variables to store the dimensions of the of the magnifier glass itself.  Then we’ll give that .container​ some shape and a background-image​:

​​:root {
​​  --magnifer-width: 85;
​​  --magnifer-height: 85;
​​}

.container {
  width: 500px;
  height: 400px;
  background-size: cover;
  background-image: url("/path/to/image.png");
  background-repeat: no-repeat;
  position: relative;
}

There are some things we already know about the magnifier before we even see it, and we can define those styles up-front, specifically the previously defined variables for the .maginifier‘s width and height:

.magnifier {
  position: absolute;
  width: calc(var(--magnifer-width) * 1px);
​​  height: calc(var(--magnifer-height) * 1px);
​​  border: 3px solid #000;
​​  cursor: none;
​​  background-image: url("/path/to/image.png");
​​  background-repeat: no-repeat;
}

It’s an absolutely-positioned little square that uses the same background image file as the .container. Do note that the calc function is solely used here to convert the unit-less value in the variable to pixels. Feel free to arrange that however you see fit as far as eliminating repetition in your code.

Now, let’s turn to the JavaScript that pulls this all together. First we need to access the CSS variable defined earlier. We will use this in multiple places later on. Then we need get the mouse position within the container because that’s the value we’ll use for the the magnifier’s background position.

​​// Get the css variables
​​let root = window.getComputedStyle(document.documentElement);
​​let magnifier_width = root.getPropertyValue("--magnifer-width");
​​let magnifier_height = root.getPropertyValue("--magnifer-height");

let container = document.querySelector(".container");
let rect = container.getBoundingClientRect();
let x = (e.pageX - rect.left);
let y = (e.pageY - rect.top);

// Take page scrolling into account
x = x - window.pageXOffset;
y = y - window.pageYOffset;

What we need is basically a mousemove event listener on the .container. Then, we will use the event.pageX or event.pageY property to get the X or Y coordinate of the mouse. But to get the exact relative position of the mouse on an element, we need to subtract the position of the parent element from the mouse position we get from the JavaScript above. A “simple” way to do this is to use getBoundingClientRect(), which returns the size of an element and its position relative to the viewport.

Notice how I’m taking scrolling into account. If there is overflow, subtracting the window pageX and pageY offsets will ensure the effect runs as expected.

We will first create the magnifier div. Next, we will create a mousemove function and add it to the image container. In this function, we will give the magnifier a class attribute. We will also calculate the mouse position and give the magnifier the left and top values we calculated earlier.

Let’s go ahead and build the magnifier when we hear a mousemove event on the .container:

// create the magnifier
let magnifier = document.createElement("div");
container.append(magnifier);

Now we need to make sure it has a class name we can scope to the CSS:

// run the function on `mousemove`
container.addEventListener("mousemove", (e) => {
  magnifier.setAttribute("class", "magnifier");
}

The example video I showed earlier positions the magnifier outside of the container. We’re gonna keep this simple and overlay it on top of the container instead as the mouse moves. We will use if statements to set the magnifier’s position only if the X and Y values are greater or equal to zero, and less than the container’s width or height. That should keep it in bounds. Just be sure to subtract the width and height of the magnifier from the X and Y values.

// Run the function on mouse move.
container.addEventListener("mousemove", (e) => {
  magnifier.setAttribute("class", "magnifier");

  // Get mouse position
  let rect = container.getBoundingClientRect();
  let x = (e.pageX - rect.left);
  let y = (e.pageY - rect.top);
  
  // Take page scrolling into account
  x = x - window.pageXOffset;
  y = y - window.pageYOffset;

  // Prevent magnifier from exiting the container
  // Then set top and left values of magnifier
  if (x >= 0 && x <= container.clientWidth - magnifier_width) {
    magnifier.style.left = x + "px";
  }
  if (y >= 0 && y <= container.clientHeight - magnifier_height) {
    magnifier.style.top = y + "px";
  }
});

Last, but certainly not least… we need to play with the magnifier’s background image a bit. The whole point is that the user gets a BIGGER view of the background image based on where the hover is taking place. So, let’s define a magnifier we can use to scale things up. Then we’ll define variables for the background image’s width and height so we have something to base that scale on, and set all of those values on the .magnifier styles:

// Magnifier image configurations
let magnify = 2;
let imgWidth = 500;
let imgHeight = 400;

magnifier.style.backgroundSize = imgWidth * magnify + "px " + imgHeight * magnify + "px";

​​Let’s take the X and Y coordinates of the magnifier’s image and apply them to the .magnifier​ element’s background-position​. As before with the magnifier position, we need to subtract the width and height of the magnifier from the X and Y values using the CSS variables.

// the x and y positions of the magnifier image
let magnify_x = x * magnify + 15;
let magnify_y = y * magnify + 15;

// set backgroundPosition for magnifier if it is within image
if (
  x <= container.clientWidth - magnifier_width &&
  y <= container.clientHeight - magnifier_height
) {
  magnifier.style.backgroundPosition = -magnify_x + "px " + -magnify_y + "px";
}

Tada!

Make it cinematic

Have you seen the Ken Burns effect? It’s classic and timeless thing where an image is bigger than the container it’s in, then sorta slides and scales slow as a slug. Just about every documentary film in the world seems to use it for image stills. If you have an Apple TV, then you’ve certainly seen it on the screen saver.

There are plenty of examples over at CodePen if you wanna get a better idea.

You’ll see that there are a number of ways to approach this. Some use JavaScript. Others are 100% CSS. I’m sure the JavaScript approaches are good for some uses cases, but if the goal is simply to subtly scale the image, CSS is perfectly suitable.

We could spice things up a bit using multiple backgrounds rather than one. Or, better yet, if we expand the rules to use elements instead of background images, we can apply the same animation to all of the backgrounds and use a dash of animation-delay to stagger the effect.

Lots of ways to do this, of course! It can certainly be optimized with Sass and/or CSS variables. Heck, maybe you can pull it off with a single <div> If so, share it in the comments!

Bonus: Make it immersive

I don’t know if anything is cooler than Sarah Drasner’s “Happy Halloween” pen… and that’s from 2016! It is a great example that layers backgrounds and moves them at varying speeds to create an almost cinematic experience. Good gosh is that cool!

GSAP is the main driver there, but I imagine we could make a boiled-down version that simply translates each background layer from left to right at different speeds. Not as cool, of course, but certainly the baseline experience. Gotta make sure the start and end of each background image is consistent so it repeats seamlessly when the animation repeats.


That’s it for now! Pretty neat that we can use backgrounds for much more than texture and contrast. I’m absolutely positive there are tons of other clever interactions we can apply to backgrounds. Temani Afif did exactly that with a bunch of neat hover effects for links. What do you have in mind? Share it with me in the comments!


Moving Backgrounds originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/moving-backgrounds/feed/ 1 376723
Classy and Cool Custom CSS Scrollbars: A Showcase https://css-tricks.com/classy-and-cool-custom-css-scrollbars-a-showcase/ https://css-tricks.com/classy-and-cool-custom-css-scrollbars-a-showcase/#comments Mon, 14 Nov 2022 13:54:26 +0000 https://css-tricks.com/?p=375019 In this article we will be diving into the world of scrollbars. I know, it doesn’t sound too glamorous, but trust me, a well-designed page goes hand-in-hand with a matching scrollbar. The old-fashioned chrome scrollbar just doesn’t fit in as …


Classy and Cool Custom CSS Scrollbars: A Showcase originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In this article we will be diving into the world of scrollbars. I know, it doesn’t sound too glamorous, but trust me, a well-designed page goes hand-in-hand with a matching scrollbar. The old-fashioned chrome scrollbar just doesn’t fit in as much.

We will be looking into the nitty gritty details of a scrollbar and then look at some cool examples.

Components of a scrollbar

This is more of a refresher, really. There are a bunch of posts right here on CSS-Tricks that go into deep detail when it comes to custom scrollbar styling in CSS.

To style a scroll bar you need to be familiar with the anatomy of a scrollbar. Have a look at this illustration:

A webpage wireframe with a scrollbar highlighting the scrollbar thumb and scrollbar track.

The two main components to keep in mind here are:

  1. The track is the background beneath the bar.
  2. The thumb is the part that the user clicks and drags around.

We can change the properties of the complete scrollbar using the vendor-prefixed::-webkit-scrollbar selector. We can give the scroll bar a fixed width, background color, rounded corners… lots of things! If we’re customizing the main scrollbar of a page, then we can use ::-webkit-scrollbar directly on the HTML element:

html::-webkit-scrollbar {
  /* Style away! */
}

If we’re customizing a scroll box that’s the result of overflow: scroll, then we can use ::-webkit-scrollbar on that element instead:

.element::-webkit-scrollbar {
  /* Style away! */
}

Here’s a quick example that styles the HTML element’s scrollbar so that it is wide with a red background:

What if we only want to change the scrollbar’s thumb or track? You guessed it — we have special prefixed pseudo-elements for those two: ::-webkit-scrollbar-thumb and ::-webkit-scrollbar-track, respectively. Here’s an idea of what’s possible when we put all of these things together:

Enough brushing up! I want to show you three degrees of custom scrollbar styling, then open up a big ol’ showcase of examples pulled from across the web for inspiration.

Simple and classy scrollbars

A custom scrollbar can still be minimal. I put together a group of examples that subtly change the appearance, whether with a slight color change to the thumb or track, or some light styling to the background.

As you can see, we don’t have to go nuts when it comes to scrollbar styling. Sometimes a subtle change is all it takes to enhance the overall user experience with a scrollbar that matches the overall theme.

Cool eye-catching scrollbars

But let’s admit it: it’s fun to go a little overboard and exercise some creativity. Here are some weird and unique scrollbars that might be “too much” in some cases, but they sure are eye-catching.

One more…

How about we take the scrollbar for a spin in a train for the thumb and tracks for the, well, the track!


Classy and Cool Custom CSS Scrollbars: A Showcase originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/classy-and-cool-custom-css-scrollbars-a-showcase/feed/ 9 375019
Overlapping Bar Charts https://css-tricks.com/overlapping-bar-charts/ https://css-tricks.com/overlapping-bar-charts/#comments Wed, 07 Sep 2022 13:46:58 +0000 https://css-tricks.com/?p=372968 As the name suggests, overlapping charts visualize two different sets of data in a single diagram. The idea is that the overlapping bars allow us to compare data, say, year-over-year. They are also useful for things like tracking progress for …


Overlapping Bar Charts originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
As the name suggests, overlapping charts visualize two different sets of data in a single diagram. The idea is that the overlapping bars allow us to compare data, say, year-over-year. They are also useful for things like tracking progress for a goal where one bar represents the goal and the other shows the current amount.

But they’re beautiful too!

A two-by-two grid of overlapping chart examples.

Your mind is probably like mine and is already starting to figure out how you’d go off and code that. Here’s how I tackled it.

The HTML

We’re going to start with markup because, well, that’s how we know what needs styling.

<div class="container">
  <div class="chart">
    <dl class="numbers">
      <dd><span>100%</span></dd>
      <!-- all the way to 0% -->
    </dl>
    <dl class="bars">
      <div>
          <dt>2018</dt>
          <dd>
            <div class="bar" data-percentage="50"></div>
            <div class="bar overlap" data-percentage="53"></div>
          </dd>
        </div>
      <div>
      <!-- more bars -->
    </dl>
  </div>
</div>

We will be using description lists (<dl>) as it is a much more semantic approach as compared to standard ordered and unordered lists. Another reason is that we are including a label within each bar. Normal lists do not have a tag within them to add a title or description unlike definition lists. In simple terms, it just makes more sense and is more readable too.

The first description list, .numbers, is the y-axis. The .bars is where the data is visualized and I’ve made a definition list to build the x-axis as well. Each list item contains a .bar and the label as a description term (dt).

And what’s up with the data attribute? The data-percentage is being used to specify the height of the bar, which ultimately represents its value on the y-axis. We could manually set it in CSS for each bar, but that is repetitive and a lot of extra code that can be replaced with a few lines of CSS.

The basic chart styles

We’re working with a lot of two-dimensional directions, so flexbox is going to be our friend for getting everything lined up. We can make the .chart element a flexible container that positions the y-axis labels and the chart beside one another in the row direction.

.chart {
  display: flex;
}

We don’t even need to specify the direction since flexbox defaults to row. Let’s do that and then add flexbox to the list of labels along the y-axis while we’re at it since we know those will run in the column direction.

.numbers {
  display: flex;
  flex-direction: column;
  list-style: none;
  margin: 0 15px 0 0;
  padding: 0;
}

Believe it or not, we can use flexbox again for the bars since, they too, are running in a row direction.

.bars {
  display: flex;
  flex: auto; /* fill up the rest of the `.chart` space */
  gap: 60px;
}

I’ve set this up so that the .bars automatically take up whatever space is leftover by the y-axis .numbers.

You probably noticed it in the HTML, but “bar” is actually two bars where one overlaps the other. I wrapped those in a generic <div> that we can use as yet another flexible container that holds the definition term (<dt>) we’re using as a label and the description details (<dd>) that holds both bar values:

.bars > div {
  align-items: center;
  display: flex;
  flex-direction: column;
  flex: 1;
  position: relative;
}

Each bar is going to be the same width, hence flex: 1. We’re relatively positioning the element while we’re at it because we’re about to absolutely position each bar and we want to make sure they stay in their containers.

Each bar has a percentage height that corresponds to the values along the vertical y-axis. You may also remember that we gave each bar a data-percentage attribute — we’re going to sprinkle in a little JavaScript that sets the height of each bar using those values.

var bars = document.querySelectorAll("dd .bar");
bars.forEach((bar) => {
  var height = bar.getAttribute("data-percentage");
  bar.style.height = height + "%";
});

That’s our basic chart!

We want to get this to where we can see the bars overlapping one another. That’s next!

Overlapping bars

The trick to get one bar to overlap another is funny because we’re often trying to prevent things from overlapping visually in CSS. But in this case, we actually want that to happen.

The bars are already overlapping; it’s just tough to tell. Notice in the HTML that the second .bar in each set has an additional .overlap class. Let’s use that to differentiate the bars. You’re totally free to choose your own styling for this. I’m adding a little padding to the .overlap bars so that they are wider than the other bars. Then I’m tweaking the stacking order using z-index so that the .overlap bars sit below the other bars.

Let’s add a legend

Legend. Such a great word, isn’t it? Packed with all kinds of meaning. In this case, it’s a more than a nice touch because, visually, we’re jamming two bars in spaces that are typically reserved for one bar. A legend provides context that explains what each bar represents.

<figure class="legend">
  <div class="type1">Estimate</div>
  <div class="type2">Actual</div>
</figure>

Using a <figure> feels correct to me. They’re often used to wrap images, but the spec says they’re used “to annotate illustrations, diagrams, photos, code listings, etc.” and we’re working with a diagram. We could probably use an unordered list to hold the items, but I went with an unsemantic <div>. If anyone has an opinion on the best way to mark this up, I’m all ears in the comments!

Once again, styling is totally up to you:

Accessibility considerations

We’ve spent a bunch of our effort on making decisions for the markup and styling of our overlapping bar chart. It’s great so far, but we’re definitely not done because there’s more we can do to make this a more accessible experience. Not everyone is a sighted web surfer, so there’s some additional work to do to convey the content in those contexts.

Specifically, we need to:

  1. check that our colors have plenty of contrast between them,
  2. allow keyboard users to tab to each overlapping bar, and
  3. make sure screen readers announce the content.

Color contrasts

We need enough contrast between:

  • the overlapping bars
  • the bars and the chart background
  • the label text and background

I did a little homework in advance on the colors I used in the examples we’ve look at so far, making sure that there is enough contrast between the foregrounds and backgrounds to achieve WCAG AA compliance.

Here’s what I’m using:

  • Overlapping bars: (#25DEAA and #696969: 3.16:1 ratio)
  • Bars and chart background (#696969 and #111: 3.43:1 ratio)
  • Y-axis label text and background (#fff and #333: 12.63: 1 ratio)

Tabbing between bars

To get this where keyboard users can select each individual bar with the Tab key, we can reach for the HTML tabindex attribute. We can use the following JavaScript inside the for-each function to add this property to each bar (both of them). We will set the tab index to 0:

bar.setAttribute("tabindex", 0);

We can also add some CSS to improve the outline when the bar is selected while we’re at it:

.bar:focus {
  outline: 1.5px solid #f1f1f1;
}

Announcing content on screen readers

Another important aspect of accessibility is making sure screen readers can announce the bars and their percentages.

We’re working with two different charts in one: a chart that shows “Estimated” values and another that shows “Actual” values. It’d be great if the user knew which bar was being announced, so let’s label them with the aria-label attribute:

<div class="bar" data-percentage="50" aria-label="Estimate">50%</div>

Notice that we have the bar’s value directly in the HTML as well. That will get announced, but we still want to visually hide it. We could use transparent text for that, but another way is to use the classic .visually-hidden trick by wrapping the value in span:

<div class="bar" data-percentage="50" aria-label="Estimate">
  <span class="visually-hidden">50%</span>
</div>
.visually-hidden {
  clip: rect(0 0 0 0); 
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap; 
  width: 1px;
}

While we’re talking about announcing content, we can probably prevent the y-axis labels from being read. It’s not like the user is missing information, as the actual percentages for each bar are already available and announced. We can use the aria-hidden attribute for that:

<dl class="numbers" aria-hidden="true">
  <dd><span>100%</span></dd>
  <dd><span>80%</span></dd>
  <dd><span>60%</span></dd>
  <dd><span>40%</span></dd>
  <dd><span>20%</span></dd>
  <dd><span>0%</span></dd>
</dl>

I also think it’s OK for screen readers to ignore the legend since it’s a visual aid:

<figure class="legend" aria-hidden="true">
  <div class="type1">Estimate</div>
  <div class="type2">Actual</div>
</figure>

The final demo

That’s a wrap!

There we go, a chart with overlapping bars! It’s a nice way to compare data and I hope you can find a use for it on some project.

Are there other ways we could have approached this? Of course! Everything we covered here is merely walking you through my thought process. I imagine some of you would have taken a different approach — if that’s you, please share! It’d be great to see other CSS layout techniques and perspectives on nailing the accessibility.


Overlapping Bar Charts originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/overlapping-bar-charts/feed/ 2 372968
Different Ways to Write CSS in React https://css-tricks.com/different-ways-to-write-css-in-react/ https://css-tricks.com/different-ways-to-write-css-in-react/#comments Wed, 22 Jun 2022 14:24:37 +0000 https://css-tricks.com/?p=366452 We’re all familiar with the standard way of linking up a stylesheet to the <head> of an HTML doc, right? That’s just one of several ways we’re able to write CSS. But what does it look like to style things …


Different Ways to Write CSS in React originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
We’re all familiar with the standard way of linking up a stylesheet to the <head> of an HTML doc, right? That’s just one of several ways we’re able to write CSS. But what does it look like to style things in a single-page application (SPA), say in a React project?

Turns out there are several ways to go about styling a React application. Some overlap with traditional styling, others not so much. But let’s count all the ways we can do it.

Importing external stylesheets

As the name suggests, React can import CSS files. The process is similar to how we link up CSS file in the HTML <head>:

  1. Create a new CSS file in your project directory.
  2. Write CSS.
  3. Import it into the React file.

Like this:

import "./style.css";

That usually goes at the top of the file where other imports happen:

import { React } from "react";
import "./Components/css/App.css";
function App() {
  return (
    <div className="main">
    </div>
  );
}
export default App;

In this example, a CSS file is imported into an App.js from the /Components/css folder.

Write inline styles

You may be used to hearing that inline styling isn’t all that great for maintainability and whatnot, but there are definitely situations (here’s one!) where it makes sense. And maintainability is less of an issue in React, as the CSS often already sits inside the same file anyway.

This is a super simple example of inline styling in React:

<div className="main" style={{color:"red"}}>

A better approach, though, is to use objects:

  1. First, create an object that contains styles for different elements.
  2. Then add it to an element using the style attribute and then select the property to style.

Let’s see that in context:

import { React } from "react";
function App() {
  const styles = {
    main: {
      backgroundColor: "#f1f1f1",
      width: "100%",
    },
    inputText: {
      padding: "10px",
      color: "red",
    },
  };
  return (
    <div className="main" style={styles.main}>
      <input type="text" style={styles.inputText}></input>
    </div>
  );
}
export default App;

This example contains a styles object containing two more objects, one for the .main class and the other for a text input, which contain style rules similar to what we’d expect to see in an external stylesheet. Those objects are then applied to the style attribute of elements that are in the returned markup.

Note that curly brackets are used when referencing styles rather than the quotation marks we’d normally use in plain HTML.

Use CSS Modules

CSS Modules… what the heck happened to those, right? They have the benefit of locally scoped variables and can be used right alongside React. But what are they, again, exactly?

Quoting the repo’s documentation:

CSS Modules works by compiling individual CSS files into both CSS and data. The CSS output is normal, global CSS, which can be injected directly into the browser or concatenated together and written to a file for production use. The data is used to map the human-readable names you’ve used in the files to the globally-safe output CSS.

In simpler terms, CSS Modules allows us to use the same class name in multiple files without clashes since each class name is given a unique programmatic name. This is especially useful in larger applications. Every class name is scoped locally to the specific component in which it is being imported.

A CSS Module stylesheet is similar to a regular stylesheet, only with a different extension (e.g. styles.module.css). Here’s how they’re set up:

  1. Create a file with .module.css as the extension.
  2. Import that module into the React app (like we saw earlier)
  3. Add a className to an element or component and reference the particular style from the imported styles.

Super simple example:

/* styles.module.css */
.font {
  color: #f00;
  font-size: 20px;
}

import { React } from "react";
import styles from "./styles.module.css";
function App() {
  return (
    <h1 className={styles.heading}>Hello World</h1>
  );
}
export default App;

Use styled-components

Have you used styled-components? It’s quite popular and allows you to build custom components using actual CSS in your JavaScript. A styled-component is basically a React component with — get ready for it — styles. Some of the features include unique class names, dynamic styling and better management of the CSS as each component has its own separate styles.

Install the styled-components npm package in the command line:

npm install styled-components

Next up, import it into the React app:

import styled from 'styled-components'

Create a component and assign a styled property to it. Note the use of template literals denoted by backticks in the Wrapper object:

import { React } from "react";
import styled from "styled-components";
function App() {
  const Wrapper = styled.div`
    width: 100%;
    height: 100px;
    background-color: red;
    display: block;
  `;
  return <Wrapper />;
}
export default App;

The above Wrapper component will be rendered as a div that contains those styles.

Conditional styling

One of the advantages of styled-components is that the components themselves are functional, as in you can use props within the CSS. This opens the door up to conditional statements and changing styles based on a state or prop.

Here’s a demo showing that off:

Here, we are manipulating the div’s display property on the display state. This state is controlled by a button that toggles the div’s state when clicked. This, in turn, toggles between the styles of two different states.

In inline if statements, we use a ? instead of the usual if/else syntax. The else part is after the semicolon. And remember to always call or use the state after it has been initialized. In that last demo, for example, the state should be above the Wrapper component’s styles.

Happy React styling!

That’s a wrap, folks! We looked at a handful of different ways to write styles in a React application. And it’s not like one is any better than the rest; the approach you use depends on the situation, of course. Hopefully now you’ve got a good understanding of them and know that you have a bunch of tools in your React styling arsenal.


Different Ways to Write CSS in React originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/different-ways-to-write-css-in-react/feed/ 8 366452