I'm creating a React application that has a hero
display on the landing page that displays one of three images: [hero-1.jpg, hero-2.png, hero-3.png]
based on the users viewport
screen
size.
I have been unsuccessful trying to find resources online that show a DRY method for achieving this, for the sake of participation, I'll leave this code that I attempted that - in theory made sense to me.
N.B. I am extremely new to Sass/Scss
snippet.html
<section className="hero is-fullheight has-background-black">
<div className="hero-body">
<div className="container">
</div>
</div>
</section>
hero.scss
$i: 1;
$breakpoint-phone: 480px;
$breakpoint-tablet: 768px;
$breakpoint-desktop: 1024px;
@mixin modifier ($i:1) {
@content;
@media only screen and (max-width:$breakpoint-phone) { $i: 2; }
@media only screen and (max-width:$breakpoint-tablet) { $i: 3; }
@media only screen and (max-width:$breakpoint-desktop) { $i: 1; }
}
.hero {
background-position: center;
background-size: cover
}
@include modifier {.hero {background-image: url('../assets/hero-#{$i}.jpg');}}
Methodology:
@include
).modifier
will modify the $i
passed to the mixin, which is interpolated in the image path.Expected Result:
Based on each breakpoint, $i
will be set to the appropriate value and change the background image dynamically.
Actual Result:
The global $i
is used, and the web page displays hero-1.jpg
.
There are a few ways you can achieve this. If I was going about this, this is how I would do it.
Also, it would be very wise to practice mobile first development. Use min-width
and go up instead of using max-width
going down. The way you currently have it structured would mean you wouldn't have a valid URL if that $i
variable wasn't set at 1 at the top of your document. Writing SASS or CSS will be much easier this way once you get used to it.
$tablet: 768px;
$desktop: 1024px;
@mixin hero-image() {
.hero {
background-position: center;
background-size: cover;
background-image: url('../assets/hero-2.jpg');
@media screen and (min-width: $tablet) {
background-image: url('../assets/hero-3.jpg');
}
@media screen and (min-width: $desktop) {
background-image: url('../assets/hero-1.jpg');
}
}
}
@include hero-image();
You're still going to have to write the background-image
property 3 times. The way you were doing it was close, but you would have had to @include modifier()
3 times in your consuming scss file. At the end of the day SASS compiles to CSS. You could potentially use a SASS function or For Loop to achieve this, but mixins can get really complicated and powerful, but also incredibly difficult to read and understand. Here's what the mixin I just showed you compiles to in CSS.
.hero {
background-position: center;
background-size: cover;
background-image: url("../assets/hero-2.jpg");
}
@media screen and (min-width: 768px) {
.hero {
background-image: url("../assets/hero-3.jpg");
}
}
@media screen and (min-width: 1024px) {
.hero {
background-image: url("../assets/hero-1.jpg");
}
}
I recommend putting your SCSS/SASS into this compiler to see your results before compiling your actual project.
Even though you are repeating background-image 3 times inside of the mixin this is very much still DRY code because you can include that one mixin everywhere your images will be shown and if you need to edit it, you can edit it in one place.