Skip to content

Instantly share code, notes, and snippets.

@seavor
Last active July 30, 2022 22:04
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save seavor/36906178b8fc045c1d81 to your computer and use it in GitHub Desktop.
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)
@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);
}
@alepee
Copy link

alepee commented Apr 2, 2015

Very nice! You should definitely send your gist to caniuse.com for reference

@seavor
Copy link
Author

seavor commented Apr 4, 2015

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.

https://github.com/seavor/vunits-poly

@floriangouy
Copy link

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