-
-
Save wfendler/6015412 to your computer and use it in GitHub Desktop.
// FILE: _mq-mixin-modern.scss | |
// | |
// standard media-query mixin with set breakpoints and the option for px-based min-width value | |
@mixin media-query($media-query){ | |
@if $media-query == "hand-and-up" { | |
@media only screen and (min-width: $hand-start) { @content; } | |
} | |
@else if $media-query == "lap-and-up" { | |
@media only screen and (min-width: $lap-start) { @content; } | |
} | |
@else if $media-query == "desk-and-up" { | |
@media only screen and (min-width: $desk-start) { @content; } | |
} | |
@else if $media-query == "wall-and-up" { | |
@media only screen and (min-width: $wall-start) { @content; } | |
} | |
@else if $media-query == "palm-and-down" { | |
@media only screen and (max-width: ($hand-start - 1px)) { @content; } | |
} | |
// If $media-query arg is not named, it expects a px value to set a min-width | |
// this should be used for all feature-based breakpoints | |
@else { | |
@media only screen and (min-width: ($media-query)) { @content; } | |
} | |
} | |
// FILE: _mq-mixin-legacy.scss | |
// | |
// sets media-query mixin to not include any media queries, it outputs all media queries small -> big to have proper cascade | |
@mixin media-query($media-query){ | |
@if $media-query == "hand-and-up" { | |
@content; | |
} | |
@else if $media-query == "lap-and-up" { | |
@content; | |
} | |
@else if $media-query == "desk-and-up" { | |
@content; | |
} | |
// Exclude wall and up, we'll assume IE won't be that huge. | |
// Exclude "palm-and-down" | |
// All feature/px-based breakpoints | |
// This may cause an improper cascade if used in conjunction with the named breakpoints above, | |
// but it's usually one or the other, not both. | |
@else { | |
@content; | |
} | |
} | |
// FILE: main.scss | |
@import "_mq-mixin-modern"; | |
@import "other-partials"; | |
// FILE: main-ie.scss | |
@import "_mq-mixin-legacy"; | |
@import "other-partials"; | |
// ^ Compile these separately and your HTML will need to look like this: | |
// | |
// <!--[if (gt IE 8) | (IEMobile)]><!--> | |
// <link href="main.css"> | |
// <!--<![endif]--> | |
// | |
// <!--[if (lt IE 9) & (!IEMobile)]> | |
// <link href="main-ie.css"> | |
// <![endif]--> |
The duplication downside:
.page-nav {
width: 100%;
@include media-query(palm-and-up) {
width: 80%;
}
@include media-query(desk-and-up) {
width: 50%;
}
}
Would give this output in main-ie.css
.page-nav {
width: 100%;
width: 80%;
width: 50%;
}
The potential issue with the px based breakpoint:
// assuming lap-and-up puts out a media query with a value greater than 400px...
.page-nav {
width: 100%;
@include media-query(lap-and-up) {
width: 50%;
}
@include media-query(400px) {
width: 80%;
}
}
Would give us this output in main-ie.css
.page-nav {
width: 100%;
width: 50%;
width: 80%;
}
The 400px
breakpoint would work properly inside of a media query, but in main-ie.css
the cascade would be incorrect. So, the only risk is using px-based breakpoint values in the incorrect order in your .scss
files. This however should never be a problem since it would be general bad-practice to author your sass media queries in a different order than they would cascade.
// FILE: _mixins.scss
@if $legacy-ie == true {
@mixin media-query($media-query){
@if $media-query == "hand-and-up" { @content; }
@else if $media-query == "lap-and-up" { @content; }
@else if $media-query == "desk-and-up" { @content; }
// Exclude "wall and up", "hand-and-down"
// All custom breakpoints
@else {
@content;
}
}
}
@else {
@mixin media-query($media-query){
@else if $media-query == "hand-and-up" {
@media only screen and (min-width:$hand-start) { @content; }
}
@else if $media-query == "lap-and-up" {
@media only screen and (min-width:$lap-start) { @content; }
}
@else if $media-query == "desk-and-up" {
@media only screen and (min-width:$desk-start) { @content; }
}
@else if $media-query == "wall-and-up" {
@media only screen and (min-width: $wall-start) { @content; }
}
@else if $media-query == "hand-and-down" {
@media only screen and (max-width: ($hand-start - 1px)) { @content; }
}
// custom breakpoints
@else {
@media only screen and ($media-query) { @content; }
}
}
}
// FILE: main.scss
$legacy-ie: false;
@import "mixins";
// FILE: main-ie.scss
$legacy-ie: true;
@import "mixins";
Set a flag for the mixin to let it know if it should utilize the Modernizr .no-mediaqueries class
The new mixin:
@mixin respond-to( $mediaQuery, $fallback ){
@if $fallback == true {
@media $mediaQuery {
@content;
}
.no-mediaqueries & {
@content;
}
}
@else {
@media $mediaQuery {
@content;
}
}
}
Here it is in use:
.object {
font-size: 12px;
@include respond-to("only screen and (min-width: 600px)", true) {
font-size: 16px;
}
}
The output would look like this:
.object { font-size: 12px; }
@media only screen and (min-width: 600px) {
.object { font-size: 16px; }
}
.no-mediaqueries .object { font-size: 16px; }
The previous one duplicates too much code within the main stylesheet. Probably too costly to be useful, although it is nice it relies on the modernizr class for feature detecting instead of just serving the "non-mediaquery" styles to IE alone.
Currently, the best route might be two "main" stylesheets, one for IE that includes a flag to tell the media query mixin to not print out the actual media queries.
// Although it is very simple, it allows for the most flexible mixin use.
// So we set some variables for our common breakpoints.
$hand-start: 520px;
$lap-start: 727px;
$desk-start: 1024px;
$wall-start: 1200px;
$palm-and-down: "only screen and (max-width: " + ($hand-start - 1px)+ ")";
$hand-and-up: "only screen and (min-width:" + $hand-start + ")";
$lap-and-up: "only screen and (min-width:" + $lap-start+ ")";
$desk-and-up: "only screen and (min-width:" + $desk-start+ ")";
$wall-and-up: "only screen and (min-width:" + $wall-start+ ")";
@mixin respond-to( $mediaQuery, $fallback ){
@if $legacy-ie == true {
@content;
}
@else {
@media $mediaQuery {
@content;
}
}
}
// It can then be used like this
.feature {
font-size: 14px;
@include respond-to( $lap-and-up ){
font-size: 20px;
}
@include respond-to( "only screen and (min-height: 700px" ) {
margin-bottom: .5em;
}
}
main.css
$legacy-ie: false;
@import "mixins";
// all other imports after this
main-legacy.css
$legacy-ie: true;
@import "mixins";
// all other imports after this
Had to rearrange the media query mixin so it would build correctly.
@mixin media-query($media-query){
@if $legacy-ie == true {
//render styles without media queries
@if $media-query == "hand-and-up" { @content; }
@else if $media-query == "lap-and-up" { @content; }
@else if $media-query == "desk-and-up" { @content; }
// exclude "wall and up", "hand-and-down"
// include custom breakpoints
@else {
@content;
}
}
@else {
@if $media-query == "hand-and-up" {
@media only screen and (min-width:$hand-start) { @content; }
}
@else if $media-query == "lap-and-up" {
@media only screen and (min-width:$lap-start) { @content; }
}
@else if $media-query == "desk-and-up" {
@media only screen and (min-width:$desk-start) { @content; }
}
@else if $media-query == "wall-and-up" {
@media only screen and (min-width: $wall-start) { @content; }
}
@else if $media-query == "hand-and-down" {
@media only screen and (max-width: ($hand-start - 1px)) { @content; }
}
// custom breakpoints
@else {
@media only screen and ($media-query) { @content; }
}
}
}
main.css
$legacy-ie: false;
@import "mixins";
// all other imports after this
main-legacy.css
$legacy-ie: true;
@import "mixins";
// all other imports after this
It causes some duplicate rules as the media-queries override themselves, but it will all be cascaded properly and the file will not be downloaded twice. The other downside is maintaining two "main" stylesheets, but that is a minor detail for how big of a maintainability win this has.