我正在创建一个在设计中具有非结构对角分隔线的布局。为了完成这个设计元素的集成,我在每个全窗口页面部分附加了一个div,并为它们设置样式:
div.diagonallySplitShader {
position: absolute;
display: block;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 9;
background: linear-gradient(95deg, rgba(200,100,0,0.6) 0%, rgba(200,100,0,0.6) 70%, rgba(0,100,200,0.6) 70.1%, rgba(0,100,200,0.6) 100%);
}
我使用3.775%的偏移量来对齐每个部分的着色器,宽度为1920px。这有效地以16:9的宽高比工作,但这不是响应式解决方案。为此,我编写了少量JS来计算基于着色器元素当前尺寸的偏移量:
(()=>{
"use strict";
function truncate(figure, decimals = 2) {
let d = Math.pow(10, decimals);
return (parseInt(figure * d) / d).toFixed(decimals);
}
function round(rnum, rlength) {
var newnumber = Math.round(rnum * Math.pow(10, rlength)) / Math.pow(10, rlength);
return newnumber;
}
// ensure diagonal layout line is responsive
function getStopOffset(angle, length, windowWidth) {
let radians = angle * Math.PI / 180,
adjacent = length,
tangent = Math.tan(radians),
opposite = adjacent * tangent,
offset = opposite / windowWidth;
return (offset * 100);
}
let sections = [
document.getElementById('landing'),
document.getElementById('news'),
document.getElementById('specialists')
];
const angle = 5;
let styleTemplate = [
/*0*/'background: linear-gradient(95deg, ',
/*1*/'rgba(200,100,0,0.6) ',
/*2*/'0%, ',
/*3*/'rgba(200,100,0,0.6) ',
/*4*/70,
/*5*/'%, ',
/*6*/'rgba(0,100,200,0.6) ',
/*7*/70.1,
/*8*/'%, ',
/*9*/'rgba(0,100,200,0.6) ',
/*10*/'100%',
/*11*/');'];
sections.forEach((e,i) => {
new Promise((resolve,reject) => {
let el,
error;
try {
let div = document.createElement('div');
div.classList.add('diagonallySplitShader');
e.appendChild(div);
el = div;
} catch(err) {
error = err;
}
resolve(el);
reject(error);
}).then(shader => {
/*
* TODO:
* - Add logic to handle window increasing in resolution greater than 1920x1080.
* - Add safegaurd to prevent resize firing before window has resized when browser is windowed/maximized.
* - (Possible) add function to handle altering gradient color stops.
*/
shader = document.getElementsByClassName('diagonallySplitShader')[i];
window.addEventListener('resize', () => {
let newOffset = getStopOffset(angle, e.clientHeight, e.clientWidth);
let background = '';
for (let j = 0; j < styleTemplate.length; ++j) {
let part = styleTemplate[j];
if (j === 4 || j === 7) {
part = truncate(parseFloat(styleTemplate[j] - (newOffset * i)));
}
background += part;
}
shader.setAttribute('style', background);
});
}).catch(error => {
console.log(error);
});
});
})();
我认为这将按照设计运作,但它根本不排队;方差约为2.25px。
Radians: 0.08726646259971647
Tangent: 0.08748866352592401
Opposite: 70.25339681131697
actual offset: 3.7750000000000057%
calculated offset: 3.659031083922759%
pixels from percentage of element width: 72.48px
calculated offset pixels: 70.25339681131697%
由css渲染并用JS计算的明显的直角三角形使用相同的源值:相邻边的5°角和相同的长度,也就是div的高度。
哪里出现水平偏移误差?
请参阅以下屏幕截图:manual offset calculated offset
造成差异的原因是css梯度背景本质上是不对称的,这源于它们出现的每个元素的高度变化。
因此解决方案相当简单;通过将渐变封装在一个统一的包装器中,将渐变与偏移分离,然后将偏移量应用于该包装器,然后一切都按预期运行。
/*
* align shaders
*/
window.addEventListener(
'load',
() =>
{
window.addEventListener(
'resize',
() =>
{
let s = document.getElementsByClassName('shader');
let o1 = round( getOpposite( 6, s[0].offsetHeight ), 1 );
let o2 = round( getOpposite( 6, s[1].offsetHeight ), 1 );
let o3 = round( getOpposite( 6, s[2].offsetHeight ), 1 );
let o12 = ( o1 + (o2 - o1) / 2 );
s[1].getElementsByClassName( 'subShader' )[0].style.transform = 'translate( ' + ( -1 * o12 ) + 'px )';
let o23 = ( ( o2 + ( o3 - o2 ) / 2 ) + o12 );
s[2].getElementsByClassName( 'subShader' )[0].style.transform = 'translate( ' + ( -1 * o23 ) + 'px )';
}
);
window.dispatchEvent( new Event( 'resize' ) );
}
);
function round( rnum, rlength )
{
return Math.round( rnum * Math.pow( 10, rlength ) ) / Math.pow( 10, rlength );
}
function getOpposite( angle, adjacent )
{
return adjacent * Math.tan( angle * Math.PI / 180 );
}