how to overwrite Susy settings at certain breakpoints - grid

I’m using Susy’s gallery setting at a small breakpoint and (because of mobile first CSS structure), its getting passed to the larger breakpoint and I can’t figure out how to clear/overwrite it to allow my divs to span full width.
tablet output:
[div] [div] [div]
desired desktop output:
[ div ]
[ div ]
[ div ]
my attempt:
div {
#include gallery(4);
#media (min-width: 900px) {
#include break;
#include full;
}
}
see FIDDLE

I'm sure you already resolved this by now, but since I came up against the same issue I thought I'd post my solution.
Add the following mixin:
#mixin reset-gallery {
&:nth-child(1n) {
margin-left: 0;
margin-right: gutter();
}
&:last-child {
margin-right: 0;
}
}
and then reset your divs as follows:
#media (min-width: 900px) {
#include reset-gallery;
#include span(full);
}
Updated fiddle here. It might not work in all situations, but it worked for me and seems to work for your case also.

Related

Using the same css layout but for differently sized media

I use CSS grid and Sass, and I use different grid layouts for different screen sizes (phone, tablet, desktop). But for some pages, I would like the same layouts but chosen at slightly bigger or smaller screens than for other pages.
Is something like that possible? Or am I approaching it from the wrong angle? My current solution (see below) works, but duplicates the styles a lot.
In more detail:
I have 3 different grids that are chosen according to the screen size.
.hero {
&__container {
grid-template-areas:
"header"
"image"
"text";
}
#media min-width: 1000px {
grid-template-areas:
"header header header"
"text ... image"
"text ... image";
}
// other definitions for this screen size
}
#media min-width: 1300px {
grid-template-areas:
"header header image"
"text ... image"
"text ... image";
}
// other definitions for this screen size
}
}
&__header {
grid-area: header;
font-size: 2.5rem;
#media min-width: 1000px {
font-size: 2.8rem;
}
#media min-width: 1300px {
font-size: 3.2rem;
}
}
...
}
They are used in about 20 similar web pages.
<div class="page_a">
<div class="hero">
<div class="hero__container">
<div class="hero__header">...</div>
<div class="hero__text">...</div>
<div class="hero__image">...</div>
</div>
</div>
</div>
The layout is very similar, but I would like to switch to different layouts at a different point based on the specifics of the content: the header text length, the size & importance of the image, etc.
What I would like to do is something like this:
.page_a {
.hero {
// redefine nothing, use defaults
}
}
.page_c {
.hero {
// the header is longer so we need a bigger screen to switch to the biggest layout
// somehow say that the 1300px layout should be used from 1500px
}
}
The only thing I managed to do is to simply redefine all the grids at each possible point (the default points + the custom points), which means the code is very repetitive:
.page_c {
.hero {
// use 1000px layout also for 1300px - the whole thing has to be repeated
#media min-width: 1300px {
grid-template-areas:
"header header header"
"text ... image"
"text ... image";
}
// other definitions for this size
}
// use 1300px layout for 1500px - the whole thing has to be repeated
#media min-width: 1500px {
grid-template-areas:
"header header image"
"text ... image"
"text ... image";
}
// other definitions for this size
}
}
}
Which means that every time I change some layout I have to go to all the places it is used at various size and change it too.
Here you go...
Your problem could be solved with SASS or SCSS, more precisely with a #mixin. I'm using SCSS because I'm more familiar with it, but you could also use SASS.
What is a #mixin?
As stated on SASS official website: Mixins allow you to define styles that can be re-used throughout your stylesheet. First you define a #mixin then you call it later in your code with an #include. Every #mixin should have a unique name. For example: define a #mixin layout_600 and call it with an #include layout_600.
Two things are important when defining a #mixin:
A #mixin should be defined before you call it with an #include. Otherwise, SCSS will try to call something that isn't defined yet (it is defined but later in your stylesheet).
A #mixin should be defined outside of your nested code (ideally at the top of your stylesheet). If you define a #mixin inside your nested code, you won't be able to call it later when you want to change default styles. The easiest way for you to understand what I mean is to show you the correct way and the wrong way.
Correct:
#mixin layout_600 {
font-size: 3rem;
color: blue;
font-weight: 700;
}
.hero {
&__header {
#media (min-width: 600px) {
#include layout_600;
}
}
}
.page_b {
.hero {
// Use the 600px layout also for the 1000px.
&__header {
#media (min-width: 1000px) {
// It will work.
#include layout_600;
}
}
}
}
Wrong:
.hero {
&__header {
#media (min-width: 600px) {
#mixin layout_600 {
font-size: 3rem;
color: blue;
font-weight: 700;
}
}
}
}
.page_b {
.hero {
// Use the 600px layout also for the 1000px.
&__header {
#media (min-width: 1000px) {
// It won't work.
#include layout_600;
}
}
}
}
You need to write a #mixin for each layout that you want to have (e.g. 600px, 1000px). You only need to do it once for every layout but you can call a particular #mixin n-times. This is perfect because:
you don't have to re-write your code, you just call a particular #mixin with an #include as many times as you want and
if you want to change your styling, you do it just once in your #mixin and the style will be changed in every place that is referring to this #mixin.
Working example
Before changing the default style
I defined three #mixins like this:
when: window width < 600px,
when: 600px < window width < 1000px and
when: window width > 1000px.
As you can see, the font-size and the color is different at different window width. The font is getting bigger and the color goes from black to blue to red as the window is getting wider. By the way, in the right upper corner I added a div that shows the current window width.
Here's a live demo before changing the default style.
After changing the default style
I decided that for the page_b I would use the 600px layout (i.e. #mixin layout_600) also for the 1000px. This can easily be done by calling the #mixin layout_600 with the #include layout_600 like this:
.page_b {
.hero {
// Use the 600px layout also for the 1000px.
&__header {
#media (min-width: 1000px) {
#include layout_600;
}
}
}
}
As you can see, the style of the page_b when window width is actually 1000px is the same as if the window width is 600px (smaller font and blue color).
Here's a live demo after changing the default style.
Customizing a #mixin
Also, it's possible to customize a #mixin if you want. For example, I used the 600px layout (i.e. #mixin layout_600) but changed the color from red to green. This can be done like this:
.page_b {
.hero {
// Use the 600px layout also for the 1000px.
&__header {
#media (min-width: 1000px) {
#include layout_600;
color: green; // Customize the mixin.
}
}
}
}
As you can see, the color should be blue (as in #mixin layout_600) but it's green.
Here's a live demo after customizing a #mixin.

Can I update SASS variables in Media Queries?

Consider the following SASS code. I want to make sure that if the screen is above 1250px then the margin-top should be 750px and then it should change depending on size. However SASS does not allow me to update the variables inside the strings.
// Above 1250px
$pageTemplateMargin:750px;
// Below 1250px
#media screen and (max-width:1250px){
$pageTemplateMargin:550px;
}
// Below 950px
#media screen and (max-width:950px){
$pageTemplateMargin:450px;
}
#media screen and (max-width:850px){
$pageTemplateMargin:150px;
}
#media screen and (max-width:750px){
$pageTemplateMargin:250px;
}
// Render the correct code
.page-template {margin-top:$pageTemplateMargin}
Is there a better way for this, as it does not work and page-template stays at 750px.
Thanks
I agree with the accepted answer that it's better to use maps in this case but I want to point out a couple of things.
Variables can actually be updated inside of media queries. The problem is that a variable defined outside of a block is a global variable while one defined within a block is a local variable. You can let sass treat a variable within a block as a global variable using the !global keyword.
$pageTemplateMargin:750px;
#media screen and (max-width:1250px){
$pageTemplateMargin: 550px !global;
}
.page-template {
margin-top: $pageTemplateMargin //will use 550px instead of 750px
}
Just want to clarify that it is possible albeit it is not appropriate in this use case.
I also suggest using a loop for your code which will prove helpful especially if you add more screen widths and margin properties so you don't need to further write more media queries.
$breakpoints: (
1200px: 10px,
1000px: 15px,
800px: 20px,
);
#each $width, $margin in $breakpoints {
#media screen and (max-width: $width) {
.element {
margin-top: $margin;
}
}
}
Hope this helps.
No, you can't (in this situation, as pointed out in the other answer).
I'd suggest using mixins to work with this:
#mixin pageTemplateMargin($px) {
margin-top: $px
}
#media screen and (max-width:1250px) {
.element { #include pageTemplateMargin(10px);}
}
#media screen and (max-width:1000px) {
.element { #include pageTemplateMargin(15px);}
}
#media screen and (max-width:800px) {
.element { #include pageTemplateMargin(20px);}
}
There's also a way of mapping through sass objects, such as:
$breakpoints: (
1200: 10px,
1000: 15px,
800: 20px,
);
#media screen and (max-width:1200px) {
.element { margin-top: map-get($breakpoints, 1200);}
}
#media screen and (max-width:1000px) {
.element { margin-top: map-get($breakpoints, 1000);}
}
#media screen and (max-width:800px) {
.element { margin-top: map-get($breakpoints, 800);}
}
This would allow you to globally change the margin by adjusting 1 variable.
Working codepen example
I have tried this then i fixed my issue. It will calculate all media-breakpoint automatically by given rate (base-size/rate-size)
$base-size: 16;
$rate-size-xl: 24;
// set default size for all cases;
:root {
--size: #{$base-size};
}
// if it's smaller then LG it will set size rate to 16/16;
// example: if size set to 14px, it will be 14px * 16 / 16 = 14px
#include media-breakpoint-down(lg) {
:root {
--size: #{$base-size};
}
}
// if it is bigger then XL it will set size rate to 24/16;
// example: if size set to 14px, it will be 14px * 24 / 16 = 21px
#include media-breakpoint-up(xl) {
:root {
--size: #{$rate-size-xl};
}
}
#function size($px) {
#return calc(#{$px} / $base-size * var(--size));
}
div {
font-size: size(14px);
width: size(150px);
}

Compass sprite - avoid using extends when including a sprite

I am using Compass to generate my sprites, and it is working beautifully, but I have run into one small annoyance. I am not able to include an individual sprite using the #include statement when inside of another #include, such as a media query mixin, which I commonly use. My sprite SCSS looks like this:
.sp {
background-repeat: no-repeat;
overflow: hidden;
line-height: 0;
font-size: 0;
text-indent: 100%;
border: 0;
}
$sp-sprite-dimensions: true;
$sp-sprite-base-class: '.sp';
$sprite-layout: smart;
#import "sp/*.png";
#include all-sp-sprites;
In another location, I am attempting to do this:
.logo {
a {
#include break($break1) {
#include sp-sprite(logo-small);
}
}
}
Nested #include statements are fine by SCSS, but it doesn't allow for #extend statements within #include statements, and apparently the sprite #include is generating an #extend statement behind the scenes, which I do not want. Anybody know a way around this?
EDIT:
It's been brought to my attention by #lolmaus that the real problem is that I am nesting an #extend inside of a media query. I guess that's not allowed, any way around it?
Using Compass sprites inside media queries is not possible, at least the way it's described in the documentation.
There are a couple of workarounds:
creating sprites manually via command line;
using a custom mixin.
Here's a SASS (SCSS) mixin for generating a sprite declaration block that will work with media queries
SCSS:
// http://compass-style.org/reference/compass/helpers/sprites/
#mixin get-sprite($map, $sprite, $repeat: no-repeat, $height: true, $width: true) {
//http://compass-style.org/reference/compass/helpers/sprites/#sprite-file
$sprite-image: sprite-file($map, $sprite);
// http://compass-style.org/reference/compass/helpers/sprites/#sprite-url
$sprite-map: sprite-url($map);
// http://compass-style.org/reference/compass/helpers/sprites/#sprite-position
$sprite-position: sprite-position($map, $sprite);
// Returns background
background: $sprite-map $sprite-position $repeat;
// http://compass-style.org/reference/compass/helpers/image-dimensions/
// Checks to see if the user wants height returned
#if $height == true {
// Gets the height of the sprite-image
$sprite-height: image-height($sprite-image);
// Returns the height
height: $sprite-height; }
// http://compass-style.org/reference/compass/helpers/image-dimensions/
// Checks to see if the user wants height returned
#if $width == true {
// Gets the width of the sprite-image
$sprite-width: image-width($sprite-image);
// Returns the width
width: $sprite-width; }
}
Usage:
$icons: sprite-map("sprites/icons/*.png"); // define a sprite map
// ... later
#media only screen and (max-width: 500px) {
.video .overlay {
#include get-sprite($icons, play-btn-large);
}
}
Source: GitHubGist - brubrant / get-sprite.scss
The following code describes how to do it
Gist: #extend Compass sprites in #media queries
/*
* A simple way to extend Compass sprite classes within media queries.
* Based on the knowledge gained here: http://www.sitepoint.com/cross-media-query-extend-sass/
* I admit it's nowhere near as clever, but it does work :)
*/
/*
* Set-up sprites for each media size
*/
// default
#import "icons-sm/*.png"
#include all-icons-sm-sprites
// corresponding sprites for larger devices
// notice that #import is within the #media query
// that's critical!
#media (min-width: $large)
#import "icons-lg/*.png"
#include all-icons-lg-sprites
/*
* Now you can do something like this
*/
// an example mixin
#mixin social-links($size)
$socials: facebook, twitter, youtube
#each $social in $socials
&.#{$social}
#extend .icons-#{$size}-#{$social}
/*
* Put to use
*/
// assuming you've got mark-up like this
<p class="social">
facebook
twitter
youtube
</p>
// you can do this
.social
a
#include social-links(sm)
width: 25px
height: 25px
#media (min-width: $large)
#include social-links(lg)
width: 50px
height: 50px

Extending selectors from within media queries with Sass

I have an item class and a compact "modifier" class:
.item { ... }
.item.compact { /* styles to make .item smaller */ }
This is fine. However, I'd like to add a #media query that forces the .item class to be compact when the screen is small enough.
On first thought, this is what I tried to do:
.item { ... }
.item.compact { ... }
#media (max-width: 600px) {
.item { #extend .item.compact; }
}
But this generates the following error:
You may not #extend an outer selector from within #media. You may only
#extend selectors within the same directive.
How would I accomplish this using SASS without having to resort to copy/pasting styles?
The simple answer is: you can't because Sass can't (or won't) compose the selector for it. You can't be inside of a media query and extend something that's outside of a media query. It certainly would be nice if it would simply take a copy of it instead of trying to compose the selectors. But it doesn't so you can't.
Use a mixin
If you have a case where you're going to be reusing a block of code inside and outside of media queries and still want it to be able to extend it, then write both a mixin and an extend class:
#mixin foo {
// do stuff
}
%foo {
#include foo;
}
// usage
.foo {
#extend %foo;
}
#media (min-width: 30em) {
.bar {
#include foo;
}
}
Extend the selector within a media query from the outside
This won't really help your use case, but it is another option:
%foo {
#media (min-width: 20em) {
color: red;
}
}
#media (min-width: 30em) {
%bar {
background: yellow;
}
}
// usage
.foo {
#extend %foo;
}
.bar {
#extend %bar;
}
Wait until Sass lifts this restriction (or patch it yourself)
There are a number of ongoing discussions regarding this issue (please don't contribute to these threads unless you have something meaningful to add: the maintainers are already aware that users desire this functionality, it's just a question of how to implement it and what the syntax should be).
https://github.com/sass/sass/issues/1050
https://github.com/sass/sass/issues/456
For the record, here is how I ended up solving the problem with only duplicating generated styles once:
// This is where the actual compact styles live
#mixin compact-mixin { /* ... */ }
// Include the compact mixin for items that are always compact
.item.compact { #include compact-mixin; }
// Here's the tricky part, due to how SASS handles extending
.item { ... }
// The following needs to be declared AFTER .item, else it'll
// be overridden by .item's NORMAL styles.
#media (max-width: 600px) {
%compact { #include compact-mixin; }
// Afterwards we can extend and
// customize different item compact styles
.item {
#extend %compact;
/* Other styles that override %compact */
}
// As shown below, we can extend the compact styles as many
// times as we want without needing to re-extend
// the compact mixin, thus avoiding generating duplicate css
.item-alt {
#extend %compact;
}
}
I believe SASS/SCSS does not support the #extend directive inside of a media query. http://designshack.net/articles/css/sass-and-media-queries-what-you-can-and-cant-do/
You might need to use a mixin instead, though the code bloat needs to be weighed against your objective.
This is the cleanest, partial solution I've found. It takes advantage of #extend where possible and falls back to mixins when inside media queries.
Cross-Media Query #extend Directives in Sass
See the article for full details but the gist is that you call a mixin 'placeholder' that then decides whether to output #extend or an #include.
#include placeholder('clear') {
clear: both;
overflow: hidden;
}
.a {
#include _(clear);
}
.b {
#include _(clear);
}
.c {
#include breakpoint(medium) {
#include _(clear);
}
}
Ultimately it may not be better than just using mixins, which is currently the accepted answer.
I use breakpoints, but it's the same idea:
#mixin bp-small {
#media only screen and (max-width: 30em) {
#content;
}
How to use it:
.sidebar {
width: 60%;
float: left;
#include bp-small {
width: 100%;
float: none;
}
}
There is a text about mixins where you can find out more about this option.
Could you restructure?
.compact { //compact-styles }
.item {}
.item.compact { #extend .compact }
#media (max-width: 600px) {
.item { #extend .compact; }
}
If I understand the documentation correctly, that should work. I think the reason the way you're trying won't work is that it doesn't see .item.compact when it's parsing the #extend, but that's an uninformed guess, so take that with a truck load of salt! :)

Media Queries - In between two widths

I'm trying to use CSS3 media queries to make a class that only appears when the width is greater than 400px and less than 900px. I know this is probably extremely simple and I am missing something obvious, but I can't figure it out. What I have come up with is the below code, appreciate any help.
#media (max-width:400px) and (min-width:900px) {
.class {
display: none;
}
}
You need to switch your values:
/* No less than 400px, no greater than 900px */
#media (min-width:400px) and (max-width:900px) {
.foo {
display:none;
}
}​
Demo: http://jsfiddle.net/xf6gA/ (using background color, so it's easier to confirm)
#Jonathan Sampson i think your solution is wrong if you use multiple #media.
You should use (min-width first):
#media screen and (min-width:400px) and (max-width:900px){
...
}
just wanted to leave my .scss example here, I think its kinda best practice, especially I think if you do customization its nice to set the width only once! It is not clever to apply it everywhere, you will increase the human factor exponentially.
Im looking forward for your feedback!
// Set your parameters
$widthSmall: 768px;
$widthMedium: 992px;
// Prepare your "function"
#mixin in-between {
#media (min-width:$widthSmall) and (max-width:$widthMedium) {
#content;
}
}
// Apply your "function"
main {
#include in-between {
//Do something between two media queries
padding-bottom: 20px;
}
}
.class {
display: none;
}
#media (min-width:400px) and (max-width:900px) {
.class {
display: block; /* just an example display property */
}
}

Resources