网页的外观和操作本质上还是和原生的有差异但可以透过配置来让体验更接近。
全萤幕模式有两种方式,Progressive Web App 尚未安装前可以透过程序触发,安装後可以透过 display 配置安装後的执行显示模式。
document.body.requestFullscreen();
Progressive Web App 主视觉、字形、操作上若配合系统会让用户能有较好且更一致的操作体验。
字形的选用上非常容易影响到使用者的观感,CSS 上可以透过 system-ui
来使用系统原生的字型。
font-family: system-ui;
当系统开启暗黑模式後,PWA 也可以透过程序上的撰写配合更改显示设定,另外对於 AMOLED 的萤幕来说,暗黑模式也可以更省电。
程序上主要透过 Media Queries Level 5 支援的 prefers-color-scheme 可以判断出使用者目前使用的系统主题。
if (window.matchMedia("(prefers-color-scheme)").media !== "not all") {
console.log("? 有支援暗黑模式");
}
@media (prefers-color-scheme: dark) {
.day.dark-scheme {
background: #333;
color: white;
}
.night.dark-scheme {
background: black;
color: #ddd;
}
}
Google 有推出了一个 dark-mode-toggle 的模组,主要是靠 Window.matchMedia()
在实作相关逻辑
const PREFERS_COLOR_SCHEME = "prefers-color-scheme";
const MEDIA = "media";
const LIGHT = "light";
const DARK = "dark";
const MQ_DARK = `(${PREFERS_COLOR_SCHEME}:${DARK})`;
const MQ_LIGHT = `(${PREFERS_COLOR_SCHEME}:${LIGHT})`;
// 看浏览器是否支援暗黑模式
const hasNativePrefersColorScheme = matchMedia(MQ_DARK).media !== NOT_ALL;
if (hasNativePrefersColorScheme) {
matchMedia(MQ_DARK).addListener(({ matches }) => {
this.mode = matches ? DARK : LIGHT;
this._dispatchEvent(COLOR_SCHEME_CHANGE, { colorScheme: this.mode });
});
}
有兴趣的大大也可以参考看看:
https://github.com/GoogleChromeLabs/dark-mode-toggle
动画来源: https://github.com/GoogleChromeLabs/dark-mode-toggle >
PWA 中 manifest 的 theme_color 设定,可以客制化 Android Chrome 的网址列的颜色,注意要和 meta 中的颜色相同。
<meta name="theme-color" content="#3c553c" />
针对操作上的 UI 优化,可以针对常见三个状态做样式设定
:hover
:focus
:active
按钮上也建议把预设的样式拿掉。
.btn:focus {
outline: 0;
/* 把外面的框框拿掉 */
}
.btn {
-webkit-tap-highlight-color: transparent;
/* 移除 highlight 的颜色 */
}
对於有触控功能原生 APP 跟网页最大的差别在很多文字是不能选取的,这时候我们也可以透过 CSS 针对这个部分进行设定。
/* 不给选 */
user-select: none;
/* 单击一次选取 */
user-select: all;
避免长按跳出浏览器的 menu
webkit-touch-callout: none;
window.addEventListener("contextmenu", (e) => {
e.preventDefault();
});
如果想要自订义,就要把浏览器预设的样式行为停用,要注意一但设为 none 变成要将很多细节去用 JS 执行
touch-action: none;
越来越多装置支援 touch 的行为,工程师在实作上其实就是针对触控、手势去实作相关事件。
touches
、targetTouches
为空,所以只能透过 changedTouches
来理解最後发生的事情针对不同的事件去做相关的事件绑定,注意一下 touchMove 不等於 mouseMove,User Agent 会分派顺序如下:
要注意的细节如下
preventDefault()
会让滑鼠事件 click 消失,但不 preventDefault()
又会同时触发 touch 跟 click,这时候就需要看情境特别处理,像是 preventDefault()
後在 touch 事件的 callback 中决定是否要用程序去触发 click5px
比较不会误触,可以用增加 padding 的方式user-scalable=no
) 就不会发生。<meta name="viewport" content="width=device-width,user-scalable=no">
// 判断是否支援
if (window.PointerEvent) {
// Pointer Event
swipeFrontElement.addEventListener(
"pointerdown",
this.handleGestureStart,
true
);
swipeFrontElement.addEventListener(
"pointermove",
this.handleGestureMove,
true
);
swipeFrontElement.addEventListener("pointerup", this.handleGestureEnd, true);
swipeFrontElement.addEventListener(
"pointercancel",
this.handleGestureEnd,
true
);
} else {
// 手指触控萤幕触发,只有一只手指也会
swipeFrontElement.addEventListener(
"touchstart",
this.handleGestureStart,
true
);
// 手指在萤幕上滑动时连续触发,一次 move 期间一秒 60 次
swipeFrontElement.addEventListener("touchmove", this.handleGestureMove, true);
// 离开萤幕时触发
swipeFrontElement.addEventListener("touchend", this.handleGestureEnd, true);
// 当系统停止监听时触发,比较少遇到,可能的情境像是接电话的时候
swipeFrontElement.addEventListener(
"touchcancel",
this.handleGestureEnd,
true
);
// Mouse Listener
swipeFrontElement.addEventListener(
"mousedown",
this.handleGestureStart,
true
);
}
>>: [Day 26] Reactive Programming - Spring WebFlux(R2DBC Repositories)
Vue.js 的自我介绍中,只有说自己接近 MVVM 但不是严格的 MVVM。 我觉得只要会「自动更...
大家好,我是西瓜,你现在看到的是 2021 iThome 铁人赛『如何在网页中绘制 3D 场景?从 ...
分享一个好用的进销存软件 eztool , 用这软件处理客人订单有一些时间了, 非常的方便又好用, ...
Jconsole介绍 Jconsole是一个JMX相容的监视工具。它使用Java虚拟机器的JMX机制...
前言 昨天问了面试网页前端的问题,收到板上前辈的许多回应真的是受宠若惊,让我感受到IT人的刚性温暖非...