显示、可见度与透明度


网页中经常做的特效,就是将元素隐藏或显示,这在网页上有几种实现的方式,主要看需求而定。

可以透过设定style属性的display来显示或隐藏元素,display设定为none时,元素就会从画面上消失,而且不列入排版考量,也就是画面上看起来,元素原本所占据的空间消失了,如果设定displayblock则会将元素以区块方式显示,像是段落与标题。设定displayinline则会将元素以内联方式显示,像是span元素。

一个简单的例子如下所示:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">

    <style type="text/css">
        #message {
            color: #ffffff;
            background-color: #ff0000;
            border-width: 10px;
            border-color: black;
            border-style: solid;
            width: 100px;
            height: 50px;
            padding: 50px;
        }
    </style>  
</head>
<body>

    <button id='toggle'>切换显示状态</button>
    <hr>
    这是一些文本!这是一些文本!这是一些文本!这是一些文本!这是一些文本!
    <div id="message">这是消息一</div>
    这是其他文本!这是其他文本!这是其他文本!这是其他文本!这是其他文本!

<script type="text/javascript">

    function style(elem, prop) {
        return window.getComputedStyle(elem, null)[prop];
    }

    function show(elem) {
        elem.style.display = elem.previousDisplay || '';
        if(style(elem, 'display') === 'none') {
            // 在 DOM 树上创建元素,获取 display 默认值后移除
            let node = document.createElement(elem.nodeName);
            document.body.appendChild(node);
            elem.style.display = style(node, 'display');
            document.body.removeChild(node);
        }
    }

    function hide(elem) {
        elem.previousDisplay = style(elem, 'display');
        elem.style.display = 'none';
    }

    document.getElementById('toggle').onclick = function() {
        let message = document.getElementById('message');
        if(style(message, 'display') === 'none') {
            show(message);
        }
        else {
            hide(message);
        }
    };
</script>  

</body>
</html>

按我观看执行结果

在上例中,透过将display设定为none来隐藏元素,并记录原有的display值,而显示元素时,若有记录原display值则恢复为原本的值,否则就使用元素预 设的值,例如<div>会设定为block,而<span>会设定为inline

设定stylevisibilityvisiblehidden亦可显示或隐藏元素,元素的visibility被设为hidden时,虽然画面上看不见,但排版仍会考虑它,也就是元素在画面上仍会占有一块空间。

就结论而言,display其实是指排版上的设定,设定为none时,表示排版上不考虑,既然不考虑排版,所以也就看不见,visibility只是单纯设定视觉效果。所以display设定为none,而visibility设定为visible时,也是看不见元素的,因为排版上不考虑,而display不是none,而visibilityhidden时,排版上会考虑,所以空间会占据,但看不到元素。

另一个亦可影响元素视觉效果的是元素的不透明度,元素的不透明度为 0 时,元素当然就完全看不见了,不过,通常不会用不透明度来显示或隐藏元素,而会用来作半透明、淡出、淡入的效果。

要设定元素的不透明度,标准上是指定 0 到 1 间的数值给styleopacity,1 表示完全不透明,0 就是透明了。

function opacity(elem, value) {
    elem.style.opacity = value;
}

元素的不透明度为 0 时,虽然看不到元素,但排版上仍会考虑它的存在,所以元素仍然占据空间。下面这个例子,实现了简单的淡出、淡入,如果元素本身有设定不透明度,淡入时会回复至原有的不透明度:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
</head>
<body>

    <button id='fadeOut'>淡出</button>
    <button id='fadeIn'>淡入</button><br>
    <img id="image" src="https://openhome.cc/Gossip/images/caterpillar_small.jpg">  

<script type="text/javascript">
    function style(elem, prop) {
        return window.getComputedStyle(elem, null)[prop];
    }

    // value 未指定时,用来获取不透明度
    function opacity(elem, value) {
        if(value === undefined) { 
            let opt = style(elem, 'opacity');
            return opt === '' ? 1 : parseFloat(opt);
        } else {
            elem.style.opacity = value;
        }
    }

    // speed 是淡入总时间,step 是动画数
    function fadeIn(elem, speed = 5000, steps = 10) {
        let targetValue = elem.previousOpacity || 1;
        delete elem.previousOpacity;

        let timeInterval = speed / steps;
        let valueStep = targetValue / steps;

        let opt = 0;
        setTimeout(function next() {
            opt += valueStep;
            if(opt < targetValue) {
                opacity(elem, opt);
                setTimeout(next, timeInterval);
            }
            else {
                opacity(elem, targetValue);
            }
        }, timeInterval);
    }     

    function fadeOut(elem, speed = 5000, steps = 10) {
        elem.previousOpacity = opacity(elem);

        let timeInterval = speed / steps;
        let valueStep = elem.previousOpacity / steps;

        let opt = elem.previousOpacity;
        setTimeout(function next() {
            opt -= valueStep;
            if(opt > 0) {
                opacity(elem, opt);
                setTimeout(next, timeInterval);
            }
            else {
                opacity(elem, 0);
            }
        }, timeInterval);
    }  

    let image = document.getElementById('image');

    document.getElementById('fadeIn').onclick = function() {
        fadeIn(image, 2000);
    };

    document.getElementById('fadeOut').onclick = function() {
        fadeOut(image, 2000);
    };  
</script>

  </body>
</html>

按我观看执行结果


展开阅读全文