Consider a stylesheet that resizes the page as the height diminishes using media
queries and transform
:
@media (max-height: 620px) {
body {
transform: scale(0.95);
}
}
@media (max-height: 590px) {
body {
transform: scale(0.90);
}
}
@media (max-height: 560px) {
body {
transform: scale(0.85);
}
}
// and so on ...
The page "zooms out" as the window height diminishes, allowing the full content to be displayed on smaller screens.
If I want to support screens smaller than 560px
height, I need to add more media
queries.
Notice that for each 30px
lost in height, we call scale with 0.05
less in the input.
Question: Is it there a way to define incremental media queries using only css
?
Follow Up: If a pure css
solution is not available, what would be the simplest way of accomplishing such effect in vanilla JS?
Edit: Thank you all for posting different solutions to this problem. I appreciate your help. Your answers helped me learn how to improve my code.
You may use as many media queries as you would like in a CSS file. Note that you may use the and operator to require multiple queries to be true, but you have to use the comma (,) as the or operator to separate groups of multiple queries. The not keyword can be used to alter the logic as well.
Using media queries. Media queries are commonly associated with CSS, but they can be used in HTML and JavaScript as well. There are a few ways we can use media queries directly in HTML.
The @media CSS at-rule can be used to apply part of a style sheet based on the result of one or more media queries. With it, you specify a media query and a block of CSS to apply to the document if and only if the media query matches the device on which the content is being used.
only screen: The only keyword is used to prevent older browsers that do not support media queries with media features from applying the specified styles. Syntax: @media only screen and (max-width: width) Example 2.
This is not possible using CSS alone. You can do this using JS by adding a window.onresize function to watch for resizing and scaling the body
of the document
. This solution also scales dynamically so you do not need to worry about breakpoints or @media queries.
function updateScale() {
let viewScale = window.innerHeight / document.documentElement.scrollHeight;
document.body.style = 'transform:scale(' + viewScale + ')';
document.documentElement.scrollHeight = window.innerHeight;
}
window.onresize = function() {
updateScale();
}
updateScale();
body {
transform-origin: 0 0;
margin: 0;
padding: 0;
overflow: hidden;
}
#block {
background-color: black;
width: 300px;
height: 4000px;
}
<div id='block'></div>
@NathanFries is correct, this isn't something that is possible with native CSS.
CSS includes viewport units for percentage-based values for your width and height, but you can't pass that onto the scale()
function.
You'd then need to tie this to some resize
event listener.
Here is a quick example that might accomplish what you're looking to do:
// @see https://github.com/WICG/EventListenerOptions/blob/9dcca95/explainer.md#feature-detection
// @example `elem.addEventListener('touchstart', fn, supportsPassive ? { passive: true } : false);`
var checkSupportPassiveEvents = function() {
var supportsPassive = false;
try {
var opts = Object.defineProperty({}, 'passive', {
get: function() {
supportsPassive = true;
},
});
window.addEventListener('testPassive', null, opts);
window.removeEventListener('testPassive', null, opts);
} catch (e) {}
return supportsPassive;
};
var supportsPassive = checkSupportPassiveEvents();
var mapRange = function(fn, inStart, inEnd, outStart, outEnd) {
if (outStart === void 0) {
outStart = inStart;
outEnd = inEnd;
inStart = 0;
inEnd = 1;
}
var inRange = inEnd - inStart,
outRange = outEnd - outStart;
return function(val) {
var original = fn((val - inStart) / inRange);
return outStart + outRange * original;
};
};
var linear = function(x) {
return x;
};
var minHeight = 320;
var maxHeight = 620;
var minScale = 0.45;
var maxScale = 1;
var screenHeightToScaleFactorInner = mapRange(linear, minHeight, maxHeight, minScale, maxScale);
var screenHeightToScaleFactor = function(height) {
if (height <= minHeight) {
return minScale;
} else if (height > maxHeight) {
return maxScale;
} else {
return screenHeightToScaleFactorInner(height);
}
};
window.addEventListener(
'resize',
function(e) {
var height = this.innerHeight;
this.document.body.style.transform = 'scale(' + screenHeightToScaleFactor(height) + ')';
},
supportsPassive ? { passive: true } : false
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With