Can someone please explain to me how this responsive approach works? This was done using the LESS framework. How is the author achieving the desired device specific behavior?
.responsive (#scale: 1) {
/*Responsive code goes here for example*/
.logo {
padding: 44px * #scale 0 33px * #scale;
img {
width: 580px * #scale;
height: 90px * #scale;
}
}
}
.responsive;
#media screen and (min-width: 480px) and (max-width: 639px) {
.responsive(0.75);
}
#media screen and (min-width: 320px) and (max-width: 479px) {
.responsive(0.5);
}
#media screen and (max-width: 319px) {
.responsive(0.25);
}
A quick lesson on the LESS framework first. It's basically a preprocessor of CSS that uses coding concepts to make CSS much more easy and readable to write.
The Less stylesheet translates to CSS as follows:
.logo {
padding: 44px 0 33px;
}
.logo img {
width: 580px;
height: 90px;
}
#media screen and (min-width: 480px) and (max-width: 639px) {
/*Responsive code goes here for example*/
.logo {
padding: 33px 0 24.75px;
}
.logo img {
width: 435px;
height: 67.5px;
}
}
#media screen and (min-width: 320px) and (max-width: 479px) {
/*Responsive code goes here for example*/
.logo {
padding: 22px 0 16.5px;
}
.logo img {
width: 290px;
height: 45px;
}
}
#media screen and (max-width: 319px) {
/*Responsive code goes here for example*/
.logo {
padding: 11px 0 8.25px;
}
.logo img {
width: 145px;
height: 22.5px;
}
}
As you can see, there is a lot of repetition in the CSS and it is not very readable (not to speak of how much work it would be to change the aspect ratio of the logo image).
At the top of the Less code, you see this:
.responsive (#scale: 1) {
/*Responsive code goes here for example*/
.logo {
padding: 44px * #scale 0 33px * #scale;
img {
width: 580px * #scale;
height: 90px * #scale;
}
}
}
The above code is referred to as a "parametric mixin", think of these as classes in object oriented languages. You can pass in variables, set variables and rules in these "mixins". In this case, #scale is the parameter and a default value of 1 is passed in. You pretty much set rules inside the mixins, except one cool thing you can do with LESS is declare "nested" rules (which is what you see with the img selector inside the .logo selector. This is essentially the same as .logo img{/*rules*/} - which is what the resulting CSS would have. Refer to this site for a complete document on LESS: http://lesscss.org/
Now the media query aspect of it. As you can see, .responsive mixin is declared first - so think of this ruleset as the "default" viewport rules.
The first media query #media screen and (min-width: 480px) and (max-width: 639px) states that for ALL viewports that have a browser width more than 480px and less than 639px, apply whatever rules specified - in this case .responsive(0.75); (so rescaling dimensions in the mixin with 0.75 as the parameter). Therefore, when this argument is met, the cascading aspect of CSS will override the default rules set out beforehand with the rules inside the media query.
The same concept would apply for the other media queries. Just think of min-width and max-width as breakpoint setters. Wherever you see a min-width defined, the rules will be applied for all viewports that are larger than or at least that defined breakpoint. Likewise, for max-width rules are applied for all viewports that are less than the specified breakpoint. And you can combine both min-width and max-width in a media query to obtain a range of viewports to apply rules to.
For more information I suggest looking at this article http://coding.smashingmagazine.com/2011/01/12/guidelines-for-responsive-web-design/
It's got an excellent explanation of responsive design, and how media query comes into play and designing a responsive webpage.
Related
This question already has answers here:
CSS media queries - Order matters?
(3 answers)
Closed 8 months ago.
So I understand the (min-width: 1400px) and (max-width: 1400px) are break points for when the CSS reaches those breakpoints it supposed to go back to its default sizing.
This is what I have done. I have my main CSS file that has its default sizing and another CSS file called query.css that controls the responsiveness of the web page.
This is how I have certain parts of both files to adjust accordingly
main CSS
.h1,.h2,.h3 {
font-size: 70px;
font-family: Cinzel, sans-serif;
}
.nav-link {
padding-left: 10rem !important;
}
query CSS
#media (min-width: 1400px) {
.h1,.h2,.h3 {
font-size: 1em;
}
.nav-link{
padding-left: 5em !important;
}
}
This is where it confuses me. The main CSS file settings are meant to be the main one, but the query CSS seems to overwrite the main CSS and it really messes up when I try and do responsive design.
I get that this min-width:1400px is meant to say if it goes from 2000px down to 1400px it must keep the min-width:1400px, but then what is the point of having the main CSS if the min-width:1400px just negates the main CSS file settings.
Its very frustrating working like this.
... it must keep the min-width:1400px ...
That's not how min-width works with media queries.
The min-width rule effectively says "apply this block of CSS if the viewport is at least this wide", in this case at least 1400px. if the viewport width is less than 1400px then the CSS surrounded by the media query will not be applied and the styles defined in main.css will take precedence.
#media (min-width: 1400px) {
/* CSS that is only applied if the viewport is >= 1400px */
}
Also, be careful about the order that the CSS files are included in the page. If query.css was included before then the media query it contains would always be over-ruled by the CSS in main.css.
It's a little more complicated than this when you take specificity in to account, but you should get the general idea.
For more info, take a look at the documentation for the media query min-width rule.
An important aspect of media-queries is structuring them correctly - especially if you're using a combination of #media (min-width: x) and #media (max-width: x).
CSS is read from top to bottom - this means that the last property applied to your desired selector will take priority, as long as its valid. This means that a more "precise/accurate" media-query rule prop will not take priority over another, if the media-query is placed below the other and both of their rules are valid. This means you can't just throw in media-queries at random locations in your CSS-file, because the CSS is just going to be overwritten.
Note that this doesn't apply on more specific selectors, but in my personal preference, I don't like mixing the specificity on a selector across multiple media-queries.
Because of this, you should always make media-query-rules with:
A descending pixel value if you're using max-width
An ascending pixel value if you're using min-width
In this example, the min-width-media-queries below the max-width-media-queries
This way, the first media-query will always take priority as long as its rules apply. When the second media-query's rule apply, that will take priority instead and so on. Try dragging the screen size of this code snippet in full page and you'll see how this code structuring works.
div {
width: 150px;
height: 150px;
background-color: red;
}
#media screen and (max-width: 412px) {
div {
background-color: green;
}
}
#media screen and (max-width: 360px) {
div {
background-color: yellow;
}
}
#media screen and (min-width: 320px) {
div {
background-color: orange;
}
}
#media screen and (min-width: 414px) {
div {
background-color: black;
}
}
#media screen and (min-width: 428px) {
div {
background-color: purple;
}
}
#media screen and (min-width: 768px) {
div {
background-color: pink;
}
}
#media screen and (min-width: 800px) {
div {
background-color: gray;
}
}
#media screen and (min-width: 820px) {
div {
background-color: limegreen;
}
}
#media screen and (min-width: 834px) {
div {
background-color: blue;
}
}
#media screen and (min-width: 884px) {
div {
background-color: teal;
}
}
<div></div>
I created a spacing-element that uses two classes:
.spacer-mobile-M = spacing height on mobile devices
.spacer-desktop-0 = spacing height on desktop devices (only active #media (min-width: 992px))
.spacer-blank {
display: block;
border: 1px solid #000;
}
.spacer-mobile-M {
height: 20px;
}
#media (min-width: 992px) {
.spacer-desktop-0 {
height: 0px;
}
}
<div class="spacer-blank spacer-mobile-M spacer-desktop-0" aria-hidden="true"></div>
The expected behavior on a 1200px wide screen would be, that the mobile-spacer is being overwritten by the desktop style (higher specificity due to media query and defined later in the code).
However, right now, the desktop spacer is being overwritten by the mobile style.
I only experience this behavior with a spacer that has a lower height than the mobile value.
Is there a rule, that classes with height: 0 or lower height than the general one (without media query) can be overwritten? I can't find anything in Google when I search for specificity.
Thanks for a short hint.
I think the problem could be use two different CSS classes for the same element. If you use media queries, why don't use the same class? For example:
.spacer {
display: block;
height: 20px;
}
#media (min-width: 992px) {
.spacer {
height: 0;
}
}
<div class="spacer" aria-hidden="true"></div>
I don't know the rest of the code, but if on desktop size you want simply hide the spacer also you can use:
#media (min-width: 992px) {
.spacer {
display: none;
}
}
I'm working on developing a style for a site and I'm using media queries as breakpoints. At the breakpoint, the page suddenly decides to listen to some style from the first interval, and some from the second. Please help.
I've tried changing the values of the viewports but this doesn't work. I hope this problem is obvious to someone with more experience than I, because I really don't know what to do.
#media (min-width: 500px) and (max-width: 768px) {
(ex.) #randomDiv {
background-color: blue;
width: 100px;
}
}
#media (min-width: 768px) and (max-width: 1023px) {
(ex.) #randomDiv {
background-color: red;
width: 300px;
}
}
When the viewport hits 768px it decides to mix styles, p.e. the background color changes to red, but the width doesn't change. Does anyone know what I'm doing wrong? After 768px (769px <) everything works just fine, as well as before 768px. Please help.
When using media queries to make your frontend code responsive, it is quite useful to think about the base or starting styles then use the queries to alter those styles in one direction only. What I mean is instead of using max-width and min-width in your queries, start with the non-query styling then override those rules with either min-width OR max-width but not both. This way the changes are seamless and you only need to think about the exact breakpoint location and which styles are being overridden.
In using this approach the order of the media queries in your stylesheet matter too. Notice the widest query goes first here, if I were using min-width instead it would go the other way around.
Try looking at this in "Full page" mode and change the size of your screen down from full width.
#randomDiv {
color: white;
margin: 0 auto;
padding: 20px;
/* only background-color & width will change */
background-color: purple;
width: 90%;
}
#media (max-width: 1023px) {
#randomDiv {
background-color: red;
width: 300px;
}
}
#media (max-width: 768px) {
#randomDiv {
background-color: blue;
width: 100px;
}
}
<div id="randomDiv">I am so random.</div>
I would like to change the following two style settings in the #media class. I am failing to find the right classes. The subclasses .col-md change their numbering throughout the document.
I am a CSS noob and have never dealt with a #media class so far (is it even a 'class' because of the # tag?).
I searched the site but I am quite lost since I do not really know how to formulate my problem.
What is the correct way to set margin-left: 10% and width: 80%?
#media (min-width: 992px)
.col-md-offset-3 {
margin-left: 25%;
}
#media (min-width: 992px)
.col-md-6 {
width: 50%;
}
EDIT based on comment:
If what you want is to impact all .col-md disregarding numbers, you can use an attribute selector:
#media (min-width: 992px) {
[class*='col-md'] {
margin-left: 10%;
width: 80%;
}
}
Otherwise, if you wish to impact only the classes .col-md-6 & .col-md-offset-3 as you have included you can do:
#media (min-width: 992px) {
.col-md-offset-3 {
margin-left: 10%;
}
.col-md-6 {
width: 80%;
}
}
This means, that the styles applied inside the #media query, will only work on media viewports with a minimum width of 992px and above.
Make sure you set these at the end of your custom stylesheet which should be loaded after bootstrap styles.
You can find more info on #media querys here.
See if this works for you:
#media (min-width: 992px) {
.col-md-offset-3 {
margin-left: 10%;
}
.col-md-6 {
width: 80%;
}
}
#media is called a media query. The CSS which needs to be applied when the condition is met all goes between curly braces following the condition.
Use col-sm for scrren size between >=768px and <992px.
For eg.,
<div class="col-md-8 col-sm-10 col-md-offset-2 col-sm-offset-1"></div>
In the above eg col-md-* will only affect when the screen size is >=992px and <1200, col-sm-* when >=768 and <992. For more info.
Regarding media query, It's like a break point.
For eg.,
p { font-size: 16px; }
#media screen and (max-width: 480px) {
p { font-size: 12px; }
}
In the above example, p tag will have font-size of 12px only on screen size less than 480px. On all other devices it will have font-size of 16px. For more info.
I'm trying to combine the use of a Sass variable with #media queries as follows:
$base_width:1160px;
#media screen and (max-width: 1170px) {$base_width: 960px;}
#media screen and (min-width: 1171px) {$base_width: 1160px;}
$base_width is then defined at various points in the stylesheet width percentage-based measurements to produce fluid layouts.
When I do this, the variable seems to be recognized properly but the conditions for the media query are not. For example, the above code produces an 1160px layout regardless of screen width. If I flip-flop the #media statements like so:
#media screen and (min-width: 1171px) {$base_width: 1160px;}
#media screen and (max-width: 1170px) {$base_width: 960px;}
It produces a 960px layout, again regardless of screen width. Also note that if I remove the first line of $base_width: 1160px; it returns an error for an undefined variable. Any ideas what I'm missing?
This is simply not possible. Since the trigger #media screen and (max-width: 1170px) happens on the client-side.
Achieving your expected result would only be possible if SASS grabbed all rules and properties in your stylesheet containing your $base_width variable and copied/changed them accordingly.
Since it won't work automatically you could do it by hand like this:
#media screen and (max-width: 1170px)
$base_width: 960px // you need to indent it to (re)set it just within this media-query
// now you copy all the css rules/properties that contain or are relative to $base_width e.g.
#wrapper
width: $base_width
...
#media screen and (min-width: 1171px)
$base_width: 1160px
#wrapper
width: $base_width
...
This is not really DRY but the best you can do.
If the changes are the same every time you could also prepare a mixin containing all the changing values, so you wouldn't need to repeat it. Additionally you can try to combine the mixin with specific changes. Like:
#media screen and (min-width: 1171px)
+base_width_changes(1160px)
#width-1171-specific-element // additional specific changes, that aren't in the mixin
display: block
And the Mixin would look like this
=base_width_changes($base_width)
#wrapper
width: $base_width
Similar to Philipp Zedler's answer, you can do it with a mixin. That lets you have everything in a single file if you want.
#mixin styling($base-width) {
// your SCSS here, e.g.
#Contents {
width: $base-width;
}
}
#media screen and (max-width: 1170px) {
#include styling($base-width: 960px);
}
#media screen and (min-width: 1171px) {
#include styling($base-width: 1160px);
}
This isn't possible with SASS, but it is possible with CSS variables (or CSS custom properties). The only drawback is browser support – but there's actually a PostCSS plugin - postcss-css-variables - that "flattens" the use of CSS variables (which gives you support for older browsers, too).
The following example works great with SASS (and with postcss-css-variables you get support for older browsers too).
SCSS
$mq-laptop: 1440px;
$mq-desktop: 1680px;
:root {
--font-size-regular: 14px;
--gutter: 1rem;
}
// The fact that we have to use a `max-width` media query here, so as to not
// overlap with the next media query, is a quirk of postcss-css-variables
#media (min-width: $mq-laptop) and (max-width: $mq-desktop - 1px) {
:root {
--font-size-regular: 16px;
--gutter: 1.5rem;
}
}
#media (min-width: $mq-desktop) {
:root {
--font-size-regular: 18px;
--gutter: 1.75rem;
}
}
.my-element {
font-size: var(--font-size-regular);
padding: 0 calc(var(--gutter) / 2);
}
This would result in the following CSS. The repetitive media queries will increase the file size, but I have found that the increase is usually negligible once the web server applies gzip (which it will usually do automatically).
CSS
.my-element {
font-size: 14px;
padding: 0 calc(1rem / 2);
}
#media (min-width: 1680px) {
.my-element {
padding: 0 calc(1.75rem / 2);
}
}
#media (min-width: 1440px) and (max-width: 1679px) {
.my-element {
padding: 0 calc(1.5rem / 2);
}
}
#media (min-width: 1680px) {
.my-element {
font-size: 18px;
}
}
#media (min-width: 1440px) and (max-width: 1679px) {
.my-element {
font-size: 16px;
}
}
Edit: Please do not use this solution. The answer by ronen is much better.
As a DRY solution, you can use the #import statement inside a media query, e.g. like this.
#media screen and (max-width: 1170px) {
$base_width: 960px;
#import "responsive_elements";
}
#media screen and (min-width: 1171px) {
$base_width: 1160px;
#import "responsive_elements";
}
You define all responsive elements in the file included using the variables defined in the media query. So, all you need to repeat is the import statement.
With #ronen's great answer and a map, there's some real power available:
#mixin styling($map) {
.myDiv {
background: map-get($map, 'foo');
font-size: map-get($map, 'bar');
}
}
#media (min-height: 500px) {
#include styling((
foo: green,
bar: 50px
));
}
#media (min-height: 1000px) {
#include styling((
foo: red,
bar: 100px
));
}
It's now possible to have lots more DRY media queries targeting .myDiv with a bunch of different values.
Map docs: https://sass-lang.com/documentation/functions/map
Example map usage: https://www.sitepoint.com/using-sass-maps/
I had the same problem.
The $menu-width variable should be 240px on the mobile view #media only screen and (max-width : 768px) and 340px on the desktop view.
So i have simply created two variables:
$menu-width: 340px;
$menu-mobile-width: 240px;
And here is how i have used it:
.menu {
width: $menu-width;
#media only screen and (max-width : 768px) {
width: $menu-mobile-width;
}
}
Two recommendations
1
Write your "default" CSS statements to be for small screens and only use media queries for larger screens. There's usually no need for a max-width media query.
Example (assuming the element has class "container")
#mixin min-width($width) {
#media screen and (max-width: $width) {
#content;
}
}
.container {
width: 960px;
#include min-width(1170px) {
width: 1160px;
}
}
2 Use CSS variables to solve the problem, if you can.
#mixin min-width($width) {
#media screen and (max-width: $width) {
#content;
}
}
:root {
--container-width: 960px;
#include min-width(1170px) {
--container-width: 1160px;
}
}
.container {
width: var(--container-width);
}
Note:
Since it will have the width of 1160px when the window has a width of 1170px, it may be better to use a width of 100% and max-width of 1160px, and the parent element might have a horizontal padding of 5px, as long as the box-sizing property is set to border-box. There are a lot of ways to solve the problem. If the parent is not a flex or grid container you might use .container { margin: auto }.
This is also possible with %placeholders.
%placeholders can be wrapped in media queries. So you could set up multiple variables to use at different screen sizes, and then the placeholders would automagically pre-process accordingly. I'm using some mixins to shorten my media query declarations here also.
In your _vars.scss file:
$width-1: 960px;
$width-2: 1160px;
In your _placeholders.scss file:
%variable-site-width {
#media screen and (max-width: 1170px) { width: $width-1; }
#media screen and (min-width: 1171px) { width: $width-2; }
}
In your page.scss file:
.wrapper. { #extend %variable-site-width; background: red; etc... }
And this will compile to something similar to:
#media screen and (max-width: 1170px) {
.wrapper { width: 960px; }
}
#media screen and (min-width: 1171px) {
.wrapper { width: 1160px; }
}
Voila!
I use this technique extensively for things like variable font sizes and a raft of other things.