Last active
July 30, 2022 22:04
-
-
Save seavor/36906178b8fc045c1d81 to your computer and use it in GitHub Desktop.
Sass Mixin for V-Units to PXs for unsupported devices (vw, vh, vmin, vmax)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@function vunit($input, $width, $height){ | |
@if unit($width) != px or unit($height) != px { | |
@error "function vunit() dimensions should contain a px unit. +[" + $width + ", " + $height +"]"; | |
} | |
// Store $input unit | |
$unit: unit($input); | |
// Remove unit from $input and convert to ratio | |
$ratio: $input / ($input * 0 + 1) / 100; | |
// Calc and store return values | |
$widthVal: floor($width * $ratio); | |
$heightVal: floor($height * $ratio); | |
$isPortrait: $width < $height; | |
@if $unit == vw { @return $widthVal; } | |
@else if $unit == vh { @return $heightVal; } | |
@else if $unit == vmax { | |
@if $isPortrait { @return $heightVal; } | |
@else { @return $widthVal; } | |
} | |
@else if $unit == vmin { | |
@if $isPortrait { @return $widthVal; } | |
@else { @return $heightVal; } | |
} | |
} | |
@mixin viewport($property, $value){ | |
// Check that the $value has a unit | |
@if unitless($value){ | |
// Throw error if the $value is unitless | |
@error "Viewport values include a specified unit. Please check your input [" + $value + "]"; | |
} @else { | |
$unit : unit($value); | |
$units: (vw, vh, vmin, vmax); | |
// Check that the unit is a V-unit | |
@if index($units, $unit) == null { | |
// Throw error if a V-unit was not used | |
@error "Viewport values include a specified V-unit. Please check your input [" + $value + "]"; | |
// V-Unit to PX logic | |
} @else { | |
// iOS Devices | |
/////////////////////////////////////////////////// | |
// iPhone3-4(s) with portrait orientation | |
@media only screen | |
and (min-device-width: 320px) | |
and (max-device-width: 480px) | |
and (-webkit-min-device-pixel-ratio: 1) // iPhone 3 | |
and (-webkit-max-device-pixel-ratio: 2) // iPhone 4 | |
and (orientation: portrait) { | |
#{$property}: vunit($value, 320px, 480px); | |
} | |
// iPhone3-4(s) with landscape orientation | |
@media only screen | |
and (min-device-width: 320px) | |
and (max-device-width: 480px) | |
and (-webkit-min-device-pixel-ratio: 1) // iPhone 3 | |
and (-webkit-max-device-pixel-ratio: 2) // iPhone 4 | |
and (orientation: landscape) { | |
#{$property}: vunit($value, 480px, 320px); | |
} | |
// iPhone5(s) with portrait orientation | |
@media only screen | |
and (min-device-width: 320px) | |
and (max-device-width: 568px) | |
and (-webkit-min-device-pixel-ratio: 2) | |
and (orientation: portrait) { | |
#{$property}: vunit($value, 320px, 568px); | |
} | |
// iPhone5(s) with landscape orientation | |
@media only screen | |
and (min-device-width: 320px) | |
and (max-device-width: 568px) | |
and (-webkit-min-device-pixel-ratio: 2) | |
and (orientation: landscape) { | |
#{$property}: vunit($value, 568px, 320px); | |
} | |
// iPads with landscape orientation (1-2 + mini). | |
@media only screen | |
and (min-device-width: 768px) | |
and (max-device-width: 1024px) | |
and (orientation:portrait) | |
and (-webkit-min-device-pixel-ratio: 1) { | |
#{$property}: vunit($value, 768px, 1024px); | |
} | |
// iPads with landscape orientation (1-2 + mini). | |
@media only screen | |
and (min-device-width: 768px) | |
and (max-device-width: 1024px) | |
and (orientation:landscape) | |
and (-webkit-min-device-pixel-ratio: 1) { | |
#{$property}: vunit($value, 1024px, 768px); | |
} | |
// Android Devices | |
/////////////////////////////////////////////////// | |
// Older Generic devices with portrait orientation | |
// (heigher gen devices seem tend take have px ratio 3) | |
@media only screen | |
and (min-device-width: 320px) | |
and (max-device-width: 533px) | |
and (-webkit-min-device-pixel-ratio: 1) | |
and (-webkit-max-device-pixel-ratio: 2) | |
and (orientation: portrait) { | |
#{$property}: vunit($value, 320px, 533px); | |
} | |
// Older Generic devices with landscape orientation | |
// (heigher gen devices seem tend take have px ratio 3) | |
@media only screen | |
and (min-device-width: 320px) | |
and (max-device-width: 533px) | |
and (-webkit-min-device-pixel-ratio: 1) | |
and (-webkit-max-device-pixel-ratio: 2) | |
and (orientation: landscape) { | |
#{$property}: vunit($value, 533px, 320px); | |
} | |
// Newer Generic devices with portrait orientation | |
// (heigher gen devices seem tend take have px ratio 3) | |
@media only screen | |
and (min-device-width: 360px) | |
and (max-device-width: 640px) | |
and (-webkit-min-device-pixel-ratio: 1) | |
and (-webkit-max-device-pixel-ratio: 2) | |
and (orientation: portrait) { | |
#{$property}: vunit($value, 360px, 640px); | |
} | |
// Newer Generic devices with landscape orientation | |
// (heigher gen devices seem tend take have px ratio 3) | |
@media only screen | |
and (min-device-width: 360px) | |
and (max-device-width: 640px) | |
and (-webkit-min-device-pixel-ratio: 1) | |
and (-webkit-max-device-pixel-ratio: 2) | |
and (orientation: landscape) { | |
#{$property}: vunit($value, 640px, 360px); | |
} | |
// Asus Nexus 7 with portrait orientation | |
@media screen | |
and (min-device-width: 601px) | |
and (max-device-width: 906px) | |
and (-webkit-min-device-pixel-ratio: 1.331) | |
and (-webkit-max-device-pixel-ratio: 1.332) | |
and (orientation: portrait) { | |
#{$property}: vunit($value, 601px, 906px); | |
} | |
// Asus Nexus 7 with landscape orientation | |
@media screen | |
and (min-device-width: 601px) | |
and (max-device-width: 906px) | |
and (-webkit-min-device-pixel-ratio: 1.331) | |
and (-webkit-max-device-pixel-ratio: 1.332) | |
and (orientation: landscape) { | |
#{$property}: vunit($value, 906px, 601px); | |
} | |
// Kindle Fire HD 7" with portrait orientation | |
// (heigher gen devices seem tend take have px ratio 3) | |
@media only screen | |
and (min-device-width: 800px) | |
and (max-device-width: 1280px) | |
and (-webkit-min-device-pixel-ratio: 1) | |
and (-webkit-max-device-pixel-ratio: 2) | |
and (orientation: portrait) { | |
} | |
// Kindle Fire HD 7" with landscape orientation | |
// (heigher gen devices seem tend take have px ratio 3) | |
@media only screen | |
and (min-device-width: 800px) | |
and (max-device-width: 1280px) | |
and (-webkit-min-device-pixel-ratio: 1) | |
and (-webkit-max-device-pixel-ratio: 2) | |
and (orientation: landscape) { | |
} | |
// Set Base value | |
// (wrap in media query to force placement at end of cascade for devices that support v-units) | |
/////////////////////////////////////////////////// | |
@media all { #{$property}: $value; } | |
} | |
} | |
} | |
.test { | |
@include viewport(font-size, 12vw); | |
} |
Thanks @alepee, this was just a prototype, I'm working on a more compact version that doesn't exponentially expand your css file (i used this version of the mixin 48 times in my 2500 line css file, and it brought it up to 5000+).
The repo for what I plan to eventually submit to caniuse.com can be found here, for anyone following up or wishing to contribute.
Hello @seavor. Thank you for this Gist. I forked it to add an else case.
Pull requests seems to be impossible with Gists, so feel free to update yours:
https://gist.github.com/floriangouy/94dd96353dd3ba9d5722b14637660e3b/revisions
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very nice! You should definitely send your gist to caniuse.com for reference