顯示、可見與不透明
September 26, 2022網頁中經常做的特效,就是將元素隱藏或顯示,這在網頁上有幾種實作的方式,主要看需求而定。
display
可以透過設定 style
屬性的 display
來顯示或隱藏元素,display
設定為 none
時,元素就會從畫面上消失,而且不列入排版考量,也就是畫面上看起來,元素原本所佔據的空間消失了,如果設定 display
為 block
則會將元素以區塊方式顯示,像是段落與標題。設定 display
為 inline
則會將元素以行內方式顯示,像是 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
。
visibility
設定 style
的 visibility
為 visible
或 hidden
亦可顯示或隱藏元素,元素的 visibility
被設為 hidden
時,雖然畫面上看不見,但排版仍會考慮它,也就是元素在畫面上仍會佔有一塊空間。
就結論而言,display
其實是指排版上的設定,設定為 none
時,表示排版上不考慮,既然不考慮排版,所以也就看不見,visibility
只是單純設定視覺效果。所以 display
設定為 none
,而 visibility
設定為 visible
時,也是看不見元素的,因為排版上不考慮,而 display
不是 none
,而 visibility
為 hidden
時,排版上會考慮,所以空間會佔據,但看不到元素。
opacity
另一個亦可影響元素視覺效果的是元素的不透明度,元素的不透明度為 0 時,元素當然就完全看不見了,不過,通常不會用不透明度來顯示或隱藏元素,而會用來作半透明、淡出、淡入的效果。
要設定元素的不透明度,標準上是指定 0 到 1 間的數值給 style
的 opacity
,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>