问题
I tried to do something similar to this: CSS Poly Fluid Sizing using calc(), vw, breakpoints and linear equations
- The wrapper shall span 100% for viewports of 600px and smaller.
- The wrapper shall span 70% for a viewport of 1800px.
- Interpolated values for all remaining viewports.
This is what I came up with so far:
#square1 {
background-color: blue;
margin: 10px 0;
width: 100%;
height: 50px;
}
#square2 {
background-color: yellow;
margin: 10px auto;
width: calc(100% - 20 * (100vw - 600px)/40);
height: 50px;
}
#square3 {
background-color:green;
margin: 10px auto;
width: calc(100% - 20 * (max(100vw, 600px) - 600px)/40);
height: 50px;
}
#square4 {
background-color: red;
margin: 10px auto;
width: calc(min(100vw, (100% - 20 * (100vw - 600px)/40)));
height: 50px;
}
<div id="square1"></div>
<div id="square2"></div>
<div id="square3"></div>
<div id="square4"></div>
Square 1 is for reference only.
Square 2 works somehow but only because I multiplied by factor 20 arbitrarily. Why does it work?
Square 3 and 4 shall avoid a horizontal overflow in case that the viewport is smaller than 600px. Both solutions don't work.
Link to Fiddle here
Any ideas? Thank you.
PS: I am no professional.
回答1:
The short answer to this question is:
/* for IE, Opera, Android and older browsers */
.rectangle { width: calc(55vw + 270px) }
@media (max-width: 600px) { .rectangle { width: 100% } }
@media (min-width: 1800px) { .rectangle { width: 70% } }
/* modern browsers */
.rectangle { width: max(70%, min(100%, calc(55vw + 270px))) }
To be able to use a 'Linear Equation' we need two points, p1(x1,y1) and p2(x2,y2), in an XY-space which depict a minimum and a maximum size at minimum and maximum viewport size.
Fortunately the OP gave us a few constraints:
- viewport width <= 600px, element width 100%
- viewport width >= 1800px, element width 70%
- viewport width > 600px and < 1800px, element width calculated with linear equation
Using those constrainsts, we can define the required two points we need for the linear equation:
- at viewport width 600px = x1 the element width is 100% (of 600px is 600px = y1)
- at viewport width 1800px = x2 the element width is 70% (of 1800px is 1260px = y2)
We have two equations at our disposal:
- Y-intercept form: y = mx + b
- point slope form: y = y1 + m(x - x1)
(check out MathIsFun: Equation of a Straight Line, easy to understand Middle School explanations, well worth the read).
where
m = (y2 - y1) / (x2 - x1)
x = always defined as 100vmin,vw,vh or vmax depending on:
- viewport width/height independent result (e.g. fontsize, padding, margin)
- either viewport width or height dependent result (e.g. width, height, padding, margin)
b = y1 - m * x1 (see halfway page: https://mathforum.org/library/drmath/view/52848.html)
substituted
- y = (y2 - y1) / (x2 - x1) * x + (y - (y2 - y1) / (x2 - x1) * x1)
- y = y1 + (y2 - y1) / (x2 - x1) * (x - x1)
Fully substituted, 'point slope form' is the shortest, but to save on CPU load, I have opted to do some manual calculations and use the Y-intercept form in my final CSS calc().
By manually calculating 'm' and 'b' using points p1(600,600) and p2(1800,1260) we will yield the final equation we can use in CSS calc():
- m = (1260 - 600) / (1800 - 600) = 0.55
- b = 600 - 0.55 * 600 = 270
- y = mx + b becomes: y = 0.55x + 270 (final equation)
width
is in this case viewport width dependent, so we use viewport unit vw
for 'x'
.rectangle { width: calc(0.55 * 100vw + 270px) } /* initially */
.rectangle { width: calc(55vw + 270px) } /* simplified */
/* with min/max constraints */
.rectangle { width: max(70%, min(100%, calc(55vw + 270px))) }
The Snippet
var root = document.documentElement;
var body = document.body;
var rectangle = document.getElementById('demo');
// Polyfill FOR IE11, used for rounding
if (Number.EPSILON === undefined) { Number.EPSILON = Math.pow(2, -52); }
function updateSpecs() {
var txt = "<table><tbody>";
txt += "<tr><td><b>#demo width/height<sup>*</sup></b>:" + "</td><td>" + rectangle.clientWidth + "/" + Math.round(((rectangle.clientWidth/root.clientWidth*100) + Number.EPSILON) * 1000) / 1000 + "%</td></tr>";
txt += "<tr><td><br></tr>";
txt += "<tr><td>Screen width/height:" + "</td><td>" + screen.width + "*" + screen.height + "</td></tr>";
txt += "<tr><td>window width/height:" + "</td><td>" + window.innerWidth + "*" + window.innerHeight + "</td></tr>";
txt += "<tr><td><br></tr>";
txt += "<tr><td>HTML width/height:" + "</td><td>" + root.clientWidth + "*" + root.clientHeight + "</td></tr>";
txt += "<tr><td>BODY width/height:" + "</td><td>" + body.clientWidth + "*" + body.clientHeight + "</td></tr>";
txt += "<tr><td><br></tr>";
txt += "<tr><td colspan='2'><b><sup>*</sup></b>check width 600px and 1800px</tr>";
txt += "</tbody></table>";
document.getElementById("specs").innerHTML = txt;
}
updateSpecs() // first run
window.addEventListener('resize', updateSpecs);
/**************************/
/* preferred global rules */
/**************************/
html,body { box-sizing: border-box; width: 100%; max-width: 100%; margin: 0 }
*::before,*::after, * { box-sizing: inherit }
/* debugging output */
#specs { width: 100%; padding: 5rem; font-family: monospace }
/* rectangle eye-candy only */
.rectangle { background-color: purple; margin: 10px auto; height: 50px }
/* use of linear equation */
/* CSS for IE, Opera, Android and older browsers */
.rectangle { width: calc(55vw + 270px) } /* p1(600,600) p2(1800,1260) */
@media (max-width: 600px) { .rectangle { width: 100% } }
@media (min-width: 1800px) { .rectangle { width: 70% } }
/* CSS for modern browsers, no @media required */
#rectangle { width: max(70%, min(100%, calc(55vw + 270px))) }
/*
NO MORE CSS BELOW THIS LINE, explanation and examples only
*/
/*
LINEAR EQUATION, generic math
math reference: https://www.mathsisfun.com/equation_of_line.html
USING POINTS
p1(x1,y1) - 1st point on an YX-graph => minimum viewport size, min required size limit
p2(x2,y2) - 2nd point on an YX-graph => maximum viewport size, max required size limit
parameter definition:
p1(vp_minimum, size_at_vp_minimum)
p2(vp_maximum, size_at_vp_maximum)
WHERE
x-axis: viewport size (either width or height of the browser window, device pixel, etc.)
y-axis: required size (of font, width, height, padding, margin, etc.)
CALCULATE
y = required responsive size, the CSS calc() result
WITH EITHER EQUATION
1) point slope form: y - y1 = m(x - x1)
simplified y = y1 + m(x - x1)
substituted y = y1 + (y2 - y1) / (x2 - x1) * (x - x1)
2) y-intercept form: y = mx + b
substituted y = (y2 - y1) / (x2 - x1) * x + (y1 - (y2 - y1) / (x2 - x1) * x1)
where
m = (y2 - y1) / (x2 - x1)
x = always defined as 100vmin,vw,vh or vmax depending on:
- viewport width/height independent result (e.g. fontsize, padding, margin)
- either viewport width or height dependent result (e.g. width, height, padding, margin)
b = y1 - m * x1 (see halfway: http://mathforum.org/library/drmath/view/52848.html)
RESULTING CSS
use either of six variations depending on
- pre calculated values
- SCSS pre-processor
- CSS custom variables
- CPU load
vx = is either 100vmin,vw,vh or vmax
1) point slope form
a) calc( y1 + m * (100vx - x1) ) or
b) calc( y1 + (y2 - y1) / (x2 - x1) * (100vx - x1) )
2) y-intercept form
a) calc( m * 100vx + b )
b) calc( m * 100vx + (y1 - m * x1) )
c) calc( (y2 - y1) / (x2 - x1) * 100vx + b )
d) calc( (y2 - y1) / (x2 - x1) * 100vx + (y1 - (y2 - y1) / (x2 - x1) * x1) )
NOTE: simplify 'mx' in (m * 100vx) by multiplying m * 100 and then use the vmin,vh,vw,vmax unit
e.g. y = 0.01 * 100vw => y = 1vw
*/
/*
LINEAR EQUATION, specific math for Stackoverflow question 54969190
points p1(x1= 600,y1= 600) where x1 = 600px (min vp) and y1 = 600 = 100% of 600 (width at vp 600px)
p2(x2=1800,y2=1260) where x2 = 1800px (max vp) and y2 = 1260 = 70% of 1800 (width at vp 1800px)
Using y-intercept form 'y=mx+b' and manually calculating 'm' and 'b' our final equation will be
m = (1260 - 600) / (1800 - 600) = 0.55
b = 600 - 0.55 * 600 = 270
y = 0.55x + 270
'width' is in this case viewport width dependent, so use viewport unit VW for 'x'
=> CSS calc(0.55 * 100vw + 270px)
=> simplified calc(55vw + 270px)
All below CSS calculation yield the same value for 'width'
*/
/* 1a) *//* width : max(70%, min(100%, calc(600px + 0.55 * (100vw - 600px))));/**/
/* 1b) *//* width : max(70%, min(100%, calc(600px + (1260 - 600) / (1800 - 600) * (100vw - 600px))));/**/
/* 2a) *//* width : max(70%, min(100%, calc(55vw + 270px))); /* preferred, least CPU intensive */
/* 2b) *//* width : max(70%, min(100%, calc(0.55 * 100vw + (600 - 0.55 * 600) * 1px)));/**/
/* 2c) *//* width : max(70%, min(100%, calc((1260 - 600) / (1800 - 600) * 100vw + 270px)));/**/
/* 2d) *//* width : max(70%, min(100%, calc((1260 - 600) / (1800 - 600) * 100vw + (600 - (1260 - 600) / (1800 - 600) * 600) * 1px)));/**/
<div id="demo" class="rectangle"></div>
<div id="specs"></div>
来源:https://stackoverflow.com/questions/54969190/responsive-fluid-design-using-linear-interpolation-for-layout