Global media queries on a react project - reactjs

I'm trying to generate a general structure of styles on scss with global breakpoints as media queries on a react project, It is possible to reuse an structure to follow media queries that we declare as global.
I'm a little bit lost on this one, any ideas?
When I mean global is that we can define the breakpoints at the root of the project and we can use any reference on the components.
Thanks in advance.

There are three ways that come to mind:
You can create a variables.scss file in which you can write the value of your breakpoints:
$sm: 576px;
$md: 768px;
$lg: 992px;
$xl: 1200px;
And the use the following variables in your scss:
#media only screen and (min-width: $sm) {
.container {
.max-width: 450px;
}
}
#media only screen and (min-width: $md) {
.container {
.max-width: 650px;
}
}
#media only screen and (min-width: $lg) {
.container {
.max-width: 900px;
}
}
#media only screen and (min-width: $xl) {
.container {
.max-width: 1000px;
}
}
Or you can the mentioned variables in your mixins.scss file to create some media query mixins:
#mixin small {
#media only screen and (min-width: $sm) {
#content;
}
}
And then, use these mixins in your main scss codes:
.container {
#include small {
max-width: 450px;
}
...
}
Or if the use cases of these media queries are limited (e.g. hiding and showing elements), you can define other mixins that include all the variations:
$displays: none inline inline-block block table table-cell table-row flex inline-flex;
$sizes: (
sm: $sm,
md: $md,
lg: $lg,
lg: $xl
);
#each $display in $displays:
#each $size-key $size in $sizes {
.display-#{size-key}-#{display} {
display: $display !important;
}
}
}
A note on importing files: I personally would import all my helper scss (variables, mixins, etc.) in a file called styles/index.scss in the root of my project among with normalizing and other global rules that I want to define, and then import this file in my other scss files:
// styles/index.scss
#import './variables.scss';
#import './mixins.scss';
...
// container.scss
#import './styles/index.scss';

Related

How to add font-awesome icons from sources with SASS?

I'm creating a React/Ionic project and using SASS for styling, but I had a hard time adding the stylings to the project.
I went to the font-awsome website, created the package, added the fonts and added the file call to my routes file. But when I use the icons, they don't appear.
the fonts folder:
font-awesome.module.scss file:
#font-face {
font-family: 'cbm-icons';
src : url('./fonts/cbm-icons.eot?uwy7j0');
src : url('./fonts/cbm-icons.eot?uwy7j0#iefix') format('embedded-opentype'),
url('./fonts/cbm-icons.ttf?uwy7j0') format('truetype'),
url('./fonts/cbm-icons.woff?uwy7j0') format('woff'),
url('./fonts/cbm-icons.svg?uwy7j0#cbm-icons') format('svg');
font-weight : normal;
font-style : normal;
font-display: block;
}
[class^="cb-"],
[class*=" cb-"] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family : 'cbm-icons' !important;
speak : never;
font-style : normal;
font-weight : normal;
font-variant : normal;
text-transform: none;
line-height : 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing : antialiased;
-moz-osx-font-smoothing: grayscale;
}
.cb-cross:before {
content: "\ea0f";
}
.cb-checkmark:before {
content: "\ea10";
}
.cb-warning:before {
content: "\ea07";
}
Here is the import in file in my routes file:
The correct way of setting this up:
First, edit scss/variables.scss and edit the $fa-font-path variable to point to where your webfonts are.
Then, just add to your main (in your case, global) scss file:
#import "./fontawesome/scss/fontawesome.scss";
Then you can use the mixins as follows:
.twitter {
#extend %fa-icon;
#extend .fab;
&:before {
content: fa-content($fa-var-twitter);
}
I followed the wiz recommendations, but tweaked it and did it my way. I took the opportunity to make some changes to my code.
So i did like this. First, I centered all my styling in global.scss. Including the style imports from ionic and the #mixin I created from font-awesome:
#import './variables.module.scss';
#import './font-awesome.module.scss';
#import '#ionic/react/css/core.css';
#import '#ionic/react/css/normalize.css';
#import '#ionic/react/css/structure.css';
#import '#ionic/react/css/typography.css';
#import '#ionic/react/css/padding.css';
#import '#ionic/react/css/float-elements.css';
#import '#ionic/react/css/text-alignment.css';
#import '#ionic/react/css/text-transformation.css';
#import '#ionic/react/css/flex-utils.css';
#import '#ionic/react/css/display.css';
#include font-awesome;
// the rest of the global styling...
}
font-awesome.scss file settings:
#mixin font-awesome {
// file settings...
}
And in the router.tsx file I left only the call to global.scss:
import 'src/presentation/styles/global.scss'
// remaining importations...
const Router: React.FC = () => {
return (
// Routes...
)
}
export default Router

How do I implement responsive typography with Bootstrap 4?

I'm building a responsive web app with Bootstrap 4. I want the font size of all text to be reduced on mobile devices compared to desktop, so I added the following to my base css file as per the Bootstrap documentation (https://getbootstrap.com/docs/4.0/content/typography/):
html {
font-size: 1rem;
}
#include media-breakpoint-up(sm) {
html {
font-size: 1.2rem;
}
}
#include media-breakpoint-up(md) {
html {
font-size: 1.4rem;
}
}
#include media-breakpoint-up(lg) {
html {
font-size: 1.6rem;
}
}
However the font size remains fixed. What am I doing wrong?
As of Bootstrap 4.3.1, there is now RFS (Responsive Font Sizing)! However, as explained in the docs, you must enable it using the $enable-responsive-font-sizes SASS variable.
RFS Demo: https://www.codeply.com/go/jr8RbeNf2M
Before Bootstrap 4.3.1, you'd can implement responsive text using SASS. However you need to specify the desired appropriate selector(s) for text that you want to resize...
#import "bootstrap/functions";
#import "bootstrap/variables";
#import "bootstrap/mixins";
html {
font-size: 1rem;
}
#include media-breakpoint-up(sm) {
html {
font-size: 1.1rem;
}
}
#include media-breakpoint-up(md) {
html {
font-size: 1.2rem;
}
}
#include media-breakpoint-up(lg) {
html {
font-size: 1.3rem;
}
}
#import "bootstrap";
Demo: https://www.codeply.com/go/5pZDWAvenE
This could also be done using CSS only (no SASS):
Demo: https://www.codeply.com/go/E1MVXqp21D
I think the easiest way is to use #media Queries. Suppose you want to change the font size responsively for a content with class "class-name" or even for entire html tag, just add your media queries to end of your css file or any place inside it.
Sample code:
/*
####################################################
M E D I A Q U E R I E S
####################################################
*/
/*
::::::::::::::::::::::::::::::::::::::::::::::::::::
Bootstrap 4 breakpoints
*/
/* Small devices (landscape phones, 544px and up) */
#media (min-width: 544px) {
.class-name {font-size: 16px;}
}
/* Medium devices (tablets, 768px and up) */
#media (min-width: 768px) {
.class-name {font-size: 30px;}
}
/* Large devices (desktops, 992px and up) */
#media (min-width: 992px) {
.class-name {font-size: 40px;}
}
/* Extra large devices (large desktops, 1200px and up) */
#media (min-width: 1200px) {
.class-name {font-size: 48px;}
}
more information can be found here
This is a Sass feature.
To have access to the media-breakpoint mixins and the size variables, you need to:
add a custom.scss file
#import "node_modules/bootstrap/scss/bootstrap";
and setup a Sass compiler
https://getbootstrap.com/docs/4.0/getting-started/theming/
Not a complete answer, but a good starting point is to enable responsive font sizes in v.4.5
$enable-responsive-font-sizes: true;
#import "../../../node_modules/bootstrap/scss/bootstrap";
Here is an alternative approach with loop
#import "bootstrap/functions";
#import "bootstrap/variables";
#import "bootstrap/mixins";
$font-sizes: (
html: ( xs: 1rem, sm: 1.2rem, md: 1.3rem),
);
#each $breakpoint in map-keys($grid-breakpoints) {
#include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
#each $name, $values in $font-sizes {
#each $n, $value in $values {
#if($infix == "-#{$n}" or ($infix == "" and $n == 'xs')) {
#{$name} { font-size: $value; }
}
}
}
}
}

Stylus: prevent media tag from interpreting strings

We have an interesting dilemma.
I have a PR open for the rupture project to namespace the functions it exports in order to add a no-conflict mode.
First the actors
There are two functions (or mixins) that are named landscape and portrait. The PR namespaces them to rupture-landscape and rupture-portrait. The #media mixin is used throughout.
And now the scene.
With some of the functions created by rupture, a string is assembled to be used with the media tag. The end result should be a normal css media query.
The problem lies with the stylus #media mixin. It seems to automatically attempt to interpret the string and expand any keywords that might exist in the scope.
Since both landscape and portrait are within scope when not using no-conflict-mode, when ever the #media tag is used with a composed string and orientation: portrait or orientation: landscape the result will prefix both the words portrait and landscape with rupture.
I've created a trivial example with a couple of attempts to fix the issue on codepen here.
Here is the code as well:
Stylus
$landscape = 'notlandscape'
$string = "only screen and (orientation landscape)"
$unquote = unquote($string)
$s = s($string)
.foo
// this is the main issue
#media $string
color: blue
These two are attempts to fix the issue
#media $unquote
color: blue
#media $s
color: blue
and the compiled result in CSS
#media only screen and (orientation: 'notlandscape') {
.foo {
color: #00f;
}
}
#media only screen and (orientation: 'notlandscape') {
.foo {
color: #00f;
}
}
#media only screen and (orientation: 'notlandscape') {
.foo {
color: #00f;
}
}
The actual desired output:
#media only screen and (orientation: landscape) {
.foo {
color: #00f;
}
}
Is there a way to prevent or circumvent this behavior?
You can try interpolation. The referenced #media page also has a section about Interpolations and variables that will provide more info and examples.
landscape = 'notlandscape'
$string = "only screen and (orientation landscape)"
.foo
#media ({$string})
color: blue
Live #codepen
Parenthesis are essential here. So it's not exactly desired output but it's still valid CSS. How to avoid that (or if it's necessary) depends on use case. One idea:
landscape = 'notlandscape'
$string = "orientation: landscape"
.foo
#media only screen and ({$string})
color: blue
Live #codepen

css modules & cssnext custom properties in react + webpack

I am just wondering what would be the best approach to using cssnext custom properties like these, alongside css modules in react.
Is there a way to share these across modules ?
:root{
--primary: pink;
--fontSize: 1rem;
--fullWidth: 100%;
--color: red;
--gutter: 1.618rem;
}
#custom-media --small-viewport (max-width: 30em);
#custom-media --large-viewport (min-width: 75em);
#custom-media --only-medium-screen (width >= 500px) and (width <= 1200px);
EDIT: *** ok i tried this, thought it worked but hasn't
:global(:root) {
--primary: pink;
--fontSize: 1rem;
--fullWidth: 100%;
--color: pink;
--gutter: 1.618rem;
}
CSS Modules should only handle selectors that are classnames (that start with a dot). So it should not be an issue and you should be able to use those custom definition as soon as they are in the file. You can use postcss-import to inline your file that contains global definitions.
Another solution is to define this global values using postcss plugin options:
https://github.com/postcss/postcss-custom-properties#variables
https://github.com/postcss/postcss-custom-media#extensions
Because the postcss-loader only transforms a single file at a time you must import your custom properties, e.g.
#import './root.css';
.foo {
color: var(--primary);
}

Stylus not parsing all variables in the same way

I'm trying to parse a list in Stylus (latest version), but it's having odd results.
$small = 200px
$medium = 400px
$large = 600px
$list = small $small,
medium $medium,
large $large
for ham in $list
#media screen and (min-width: ham[1])
.{ham[0]}
width ham[1]
yields
#media screen and (min-width: ham[1]) {
.small {
width: 200px;
}
}
#media screen and (min-width: ham[1]) {
.medium {
width: 400px;
}
}
#media screen and (min-width: ham[1]) {
.large {
width: 600px;
}
}
The ham[1] variable isn't getting parsed in the media query regardless of whether I wrap it in {} or not, but it's parsed elsewhere just fine. What am I missing here?
Currently, media queries do not allow for interpolation. What you can do however is use one variable. Just construct the query beforehand for now :
$small = 200px
$medium = 400px
$large = 600px
$list = small $small,
medium $medium,
large $large
for ham in $list
query = 'screen and (min-width: %s)' % ham[1]
#media query
.{ham[0]}
width ham[1]
UPDATE :
With Stylus 0.44 (or 0.45), they now do !

Resources