Automate pixel fallback using REM units throughout a project - css

I checked the following article in which it presented the following mixing:
rem font size with pixel fallback
#function calculateRem($size) {
$remSize: $size / 16px;
#return $remSize * 1rem;
}
#mixin font-size($size) {
font-size: $size;
font-size: calculateRem($size);
}
I feel very confortable using rem on my projects, after placing font-size: 62.5% on the html so 1rem = 10pixels.
But I would like to know if there is a mixing or a method to create a pixel fallback for any rem used in a whole project, as for example:
&:before{
color: white;
margin: 0 0.5rem 0 0;
left: 0;
text-align: center;
top: 0;
width: 3.2rem;
}
In this case the margin-right = 5pixels and width 32pixels. The issue with rem units is that IE8, Opera mini or Safari 3.2 is not supported. So the site would not be correctly visible from any of these browsers.
Is there a way to automate the pixel fallback using rem throughout a project?

Here is a solution so you can use the rem to px mixin for any property:
html {
font-size: 62.5%;
}
#function calculateRem($size) {
$remSize: $size / 10px;
#return #{$remSize}rem;
}
#mixin rem($propertie, $value) {
#{$propertie}: $value;
#{$propertie}: calculateRem($value);
}
p {
font-size: calculateRem(32px);
#include rem(width, 100px);
#include rem(margin, 50px);
}
OUTPUT
html {
font-size: 62.5%;
}
p {
font-size: 3.2rem;
width: 100px; /* Fallback */
width: 10rem;
margin: 50px; /* FallBack */
margin: 5rem;
}
An example: http://sassmeister.com/gist/e888e641925002b5895c

This solution will work with shortcut properties that contain mixed values.
// Global Var
$root-font-size: 16;
#mixin rem($property, $values) {
$pxvalues: null;
$remvalues: null;
#each $value in $values{
$pxvalue: null;
$remvalue: null;
#if type-of($value) == 'number'{
#if ($value > 0 or $value < 0){
$pxvalue: ($value)+px;
$remvalue: ($value / $root-font-size)+rem;
} #else {
$pxvalue: $value;
$remvalue: $value;
}
} #else {
$pxvalue: $value;
$remvalue: $value;
}
$pxvalues: append($pxvalues, $pxvalue);
$remvalues: append($remvalues, $remvalue);
}
#{$property}: $pxvalues;
#{$property}: $remvalues;
}
// Usage: pass pixel values without units
.foo{
#include rem(margin, 80 auto);
}
Output:
.foo{
margin: 80px auto;
margin: 5rem auto;
}

Related

Looping through Breakpoints via SCSS

Current I have the below, but it would be great to easily loop through the break points if possible.
#for $i from 1 through 200 {
.m-#{$i}px {
margin: 1px * $i !important;
&-sm {
#include media-breakpoint-up(sm) {
margin: 1px * $i !important;
}
}
&-md {
#include media-breakpoint-up(md) {
margin: 1px * $i !important;
}
}
&-lg {
#include media-breakpoint-up(lg) {
margin: 1px * $i !important;
}
}
&-xl {
#include media-breakpoint-up(xl) {
margin: 1px * $i !important;
}
}
&-xxl {
#include media-breakpoint-up(xxl) {
margin: 1px * $i !important;
}
}
}
}
There is more of this code to cover:
mt
mx
my
mr
ml
Plus I have something similar setup for padding and a few other elements, it would be great to reduce the code as it is taking a fair while to generate the code.
Any help would be great.
You can store your breakpoints in a list and use a #each loop:
$breakpoints: sm, md, lg, xl, xxl;
#for $i from 1 through 200 {
.m-#{$i}px {
margin: 1px * $i !important;
#each $breakpoint in $breakpoints {
&-#{$breakpoint} {
#include media-breakpoint-up($breakpoint) {
margin: 1px * $i !important;
}
}
}
}
}

Using wildcard as a value

Is there a way to use wildcard to write all these twenty rules as one:
.margin-bottom-1rem {
margin-bottom: 1rem;
}
.margin-bottom-2rem {
margin-bottom: 2rem;
}
...
.margin-bottom-20rem {
margin-bottom: 20rem;
}
I found many resources about capturing all the class names, but none about using a part of the captured name as a value. If this is not possible with wildcards, is there another workaround to avoid these duplicated rules?
SCSS
$sizes: 1rem, 2rem, 5rem, 10rem, 20rem;
#each $size in $sizes {
.margin-bottom-#{$size} {
margin-bottom: $size;
}
}
SASS
$sizes: 1rem, 2rem, 5rem, 10rem, 20rem
#each $size in $sizes
.margin-bottom-#{$size}
margin-bottom: $size
Both produce this:
.margin-bottom-1rem {
margin-bottom: 1rem;
}
.margin-bottom-2rem {
margin-bottom: 2rem;
}
.margin-bottom-5rem {
margin-bottom: 5rem;
}
.margin-bottom-10rem {
margin-bottom: 10rem;
}
.margin-bottom-20rem {
margin-bottom: 20rem;
}
Do something for every element
https://sass-lang.com/documentation/values/lists#do-something-for-every-element

How to inject literal string into scss #mixin

Considering this following scss code:
#mixin homeSlider(
$dim: 150px,
$h1: "h1 { font-size: 4em; margin-top: 0; }"
){
section {
margin-top: -$dim;
}
$h1;
}
#include homeSlider( $dim: 50px, $h1: "h1 { font-size: 3em; margin-top: 0; }" )
I need to know how is it possible to achieve my goal
Try this
#mixin homeSlider($dim, $h1-font-size){
section {
margin-top: -$dim;
h1 {
font-size: $h1-font-size;
margin-top: 0;
}
}
}
#include homeSlider(50px, 3em;) /* $dim = 50px - $h1-font-size = 3em; */

SASS issue with calling mixin

My SASS code:
// rem calculator
#function calculateRem($size) {
$remSize: $size / 16px;
#return #{$remSize}rem;
}
#mixin fontsize($size) {
font-size: $size; //Fallback in px
font-size: calculateRem($size);
}
// variables
$font-size-regular: fontsize(16px);
// css
body {
font-size: $font-size-regular;
}
This outputs: font-size: fontsize(16px);
Using #include fontsize(16px); does work. but I want to put it in a variable if possible
You may do this
// rem calculator
#function calculateRem($size) {
$remSize: $size / 16px;
#return #{$remSize}rem;
}
#mixin fontsize($size) {
font-size: $size; //Fallback in px
font-size: calculateRem($size);
}
// variables
$font-size-regular: 16px;
// css
body {
#include fontsize($font-size-regular);
}

Using if statement on css selectors - SASS

I am working on a stylesheet for a multisite.
I have to declare a font-size in one variable, and the variable would change depending on the selectors. Eg:
$newfont : 10px;
i am attempting this which of course is not working:
#if ( #header ) {
$newfont: 30px;
}# else if ( #footer ) {
$newfont: 25px;
}
Can someone please point out what i am doing wrong?
I am sorry but why don't you use
#header{
font-size: 30px;
}
#footer{
font-size:25px;
}
and as pointed out in the comment below you can use a mixin.
I'm not sure what you are trying to achieve, but #if requires a SassScript expression. What you are passing is actually a selector. If you want to apply different font size for different containers I'll suggest to use a function or mixin. For example:
#function get-font-size($type) {
#if $type == "header" {
#return 30px;
} #else if $type == "footer" {
#return 25px;
}
}
#header {
font-size: get-font-size("header");
}
#footer {
font-size: get-font-size("footer");
}
The code produces:
#header {
font-size: 30px;
}
#footer {
font-size: 25px;
}
You may even control the process with a variable as you tried actually:
$newfontsize: 30px;
#mixin update-font-size($size) {
$newfontsize: $size;
}
#function get-font-size() {
#return $newfontsize;
}
#header {
font-size: get-font-size();
}
#include update-font-size(15px);
#footer {
font-size: get-font-size();
}
The simplest solution is to just use more variables. This is how most theming libraries do it.
$header-font-size: 30px !default;
$footer-font-size: 25px !default;
#header{
font-size: $header-font-size;
}
#footer{
font-size: $footer-font-size;
}

Resources