从css渲染的值与用JS计算的值之间存在这种差异的原因是什么?

问题描述 投票:2回答:1

我正在创建一个在设计中具有非结构对角分隔线的布局。为了完成这个设计元素的集成,我在每个全窗口页面部分附加了一个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

javascript css
1个回答
0
投票

造成差异的原因是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 );
}
© www.soinside.com 2019 - 2024. All rights reserved.