I have a fixed-size <div>
with some complex content (including text and background images). This <div>
has its size hardcoded in pixels (and its content depends on this size, and content positions are hardcoded in pixels as well).
Here is a greatly simplified example: http://jsfiddle.net/dg3kj/.
I need to scale that div and the content inside it, maintaining its aspect ratio, so it fits the window.
A solution that would not require me to manually change <div>
contents is preferable (it is generated dynamically and is a bunch of very messy legacy code which I would like to avoid touching). JavaScript (jQuery) solutions are OK (including ones that change the generated content — as long as it is done post-factum of generation itself).
I tried to play with transform: scale()
, but it did not yield satisfactory results. See here: http://jsfiddle.net/sJkLn/1/. (I expect the red background to be not visible — i.e. outermost <div>
size should not be stretched by the original dimensions of scaled down <div>
.)
Any clues?
Answer: Use the CSS display Property You can simply use the CSS display property with the value inline-block to make a <div> not larger than its contents (i.e. only expand to as wide as its contents).
To scale the contents of a div by a percentage with CSS, we can set the zoom and -moz-transform CSS properties. to scale the contents of the element with ID myContainer by a factor of 0.5 by setting zoom to 0.5 and -moz-transform to scale(0.5) .
The scale() CSS function defines a transformation that resizes an element on the 2D plane. Because the amount of scaling is defined by a vector, it can resize the horizontal and vertical dimensions at different scales. Its result is a <transform-function> data type.
The transform CSS property lets you rotate, scale, skew, or translate an element. It modifies the coordinate space of the CSS visual formatting model.
let outer = document.getElementById('outer'), wrapper = document.getElementById('wrap'), maxWidth = outer.clientWidth, maxHeight = outer.clientHeight; window.addEventListener("resize", resize); resize(); function resize(){let scale, width = window.innerWidth, height = window.innerHeight, isMax = width >= maxWidth && height >= maxHeight; scale = Math.min(width/maxWidth, height/maxHeight); outer.style.transform = isMax?'':'scale(' + scale + ')'; wrapper.style.width = isMax?'':maxWidth * scale; wrapper.style.height = isMax?'':maxHeight * scale; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; background: #e6e9f0; margin: 10px 0; } #wrap { position: relative; width: 640px; height: 480px; margin: 0 auto; } #outer { position: relative; width: 640px; height: 280px; background: url('https://source.unsplash.com/random') no-repeat center center; transform-origin: 0% 50%; border-radius: 10px; box-shadow: 0px 3px 25px rgba(0, 0, 0, 0.2); overflow: hidden; } #outer:before { content: ""; position: absolute; bottom: 0; width: 100%; height: 100px; -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px); } #profile { background: url('https://source.unsplash.com/random/300x300') no-repeat center center; position: absolute; width: 60px; height: 60px; bottom: 0; margin: 20px; border-radius: 100px; background-size: contain; } #content { font-size: 20px; position: absolute; left: 0px; bottom: 0; margin: 30px 100px; color: white; text-shadow: 0 1px 2px rgba(0,0,0,0.5); } #content div:last-child { font-size: 15px; opacity: 0.7; }
<div id="wrap"> <div id="outer"> <div id="profile"></div> <div id="content"> <div>Monwell Partee</div> <div>UX / UI Designer</div> </div> </div> </div>
I took the answer from dc5, and put it in a small function that allows you to set the scale based on window.
function scaleBasedOnWindow(elm, scale=1, fit=false){ if(!fit){ elm.style.transform='scale('+scale/Math.min(elm.clientWidth/window.innerWidth,elm.clientHeight/window.innerHeight)+')'; }else{ elm.style.transform='scale('+scale/Math.max(elm.clientWidth/window.innerWidth,elm.clientHeight/window.innerHeight)+')'; } }
if you want the element to fit, and not get cut off, just change Math.min
to Math.max
, or just set the fit parameter of this function to true.
Minified Version:
function scaleBasedOnWindow(elm,scale=1,fit){if(!fit){elm.style.transform='scale('+scale/Math.min(elm.clientWidth/window.innerWidth,elm.clientHeight/window.innerHeight)+')';}else{elm.style.transform='scale('+scale/Math.max(elm.clientWidth/window.innerWidth,elm.clientHeight/window.innerHeight)+')';}}
In case anyone building an full-screen application of let's say 1920x1080 and wants to perfectly fit in a smaller screen - e.g 1366x768. This is what I did in Vue.js - but can be done with pure js and css - based on answer above - the main importance is that I set the original width and height specifically otherwise it wasn't working for me:
App.vue (conditional class if lowres exists in localStorage)
<template>
<div id="external-app-wrapper" :class="{lowres: isLowRes}">
<div id="internal-app-wrapper">
<router-view />
</div>
</div>
</template>
computed: {
isLowRes() {
return localStorage.getItem('lowres') !== null
}
}
scale is calculated as: 1366/1920 and 786/1080
#external-app-wrapper {
width: 1920px;
height: 1080px;
}
.lowres #internal-app-wrapper {
transform-origin: top left;
transform: scale(0.71145833333, 0.71111111111);
}
router.js (resolution is optional)
{
path: '/app/:resolution?',
name: 'App Home',
component: () => import('@/components/routes/HomeRoute'),
meta: {
title: 'App Home'
}
}
in HomeRoute.vue I have:
mounted() {
if (this.$route.params.resolution === 'lowres') {
localStorage.setItem('lowres', 'true')
this.$router.push({ path: '/app' })
this.$router.go()
} else if (this.$route.params.resolution === 'highres') {
localStorage.removeItem('lowres')
this.$router.push({ path: '/app' })
this.$router.go()
}
}
so navigating to /app/lowres
redirects to /app
and shrinks the whole application
and redirecting to /app/highres
redirects to /app
and resolution is back to normal
Hope someone finds it useful :)
Pure JS Based on dc5
's answer;
Scales based on window resize
let outer = document.getElementById('outer'),
wrapper = document.getElementById('wrap'),
maxWidth = outer.clientWidth,
maxHeight = outer.clientHeight;
window.addEventListener("resize", resize);
resize();
function resize(){let scale,
width = window.innerWidth,
height = window.innerHeight,
isMax = width >= maxWidth && height >= maxHeight;
scale = Math.min(width/maxWidth, height/maxHeight);
outer.style.transform = isMax?'':'scale(' + scale + ')';
wrapper.style.width = isMax?'':maxWidth * scale;
wrapper.style.height = isMax?'':maxHeight * scale;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
background: #e6e9f0;
margin: 0;
padding: 0;
}
#wrap {
position: relative;
width: 640px;
height: 480px;
margin: 0 auto;
}
#outer {
position: relative;
width: 640px;
height: 280px;
background: url('https://source.unsplash.com/random') no-repeat center center;
transform-origin: 0% 50%;
border-radius: 10px;
box-shadow: 0px 3px 25px rgba(0, 0, 0, 0.2);
overflow: hidden;
margin-top: 10px;
}
#outer:before {
content: "";
position: absolute;
bottom: 0;
width: 100%;
height: 100px;
-webkit-backdrop-filter: blur(20px);
backdrop-filter: blur(20px);
}
#profile {
background: url('https://source.unsplash.com/random/300x300') no-repeat center center;
position: absolute;
width: 60px;
height: 60px;
bottom: 0;
margin: 20px;
border-radius: 100px;
background-size: contain;
}
#content {
font-size: 20px;
position: absolute;
left: 0px;
bottom: 0;
margin: 30px 100px;
color: white;
text-shadow: 0 1px 2px rgba(0,0,0,0.5);
}
#content div:last-child {
font-size: 15px;
opacity: 0.7;
}
<div id="wrap">
<div id="outer">
<div id="profile"></div>
<div id="content">
<div>Monwell Partee</div>
<div>UX / UI Designer</div>
</div>
</div>
</div>
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