当您模拟智能手机时,输入范围在可滚动 div 中不起作用
Input range won't work in an scrollable div when you simulate a smartphone
我在 div
中有一个 input range
包含在一个比内部 div
小的外部 div
中。最后的结果是我的内层div
水平滚动(因为外层潜水有overflow: scroll
),而input range
是它的子
为了自定义范围,我用 appearance: none
删除了 CSS 中的外观。现在,这就是发生的事情。当我在 Chrome 开发者工具中检查它时(实际上我使用的是 Brave,但我猜它在 Chrome 中与我在 Chromium 中测试的相同,并且是相同的)并且智能手机选项处于活动状态,99% 的时间,如果我尝试移动范围手柄,它会移动整个 div
。现在,如果我禁用智能手机选项,它就可以正常工作。此外,如果我保留智能手机选项并从 CSS 中删除 appearance: none
,它也可以正常工作,但我对范围的自定义会消失。有人知道这是怎么回事吗?
PS.: 在 Firefox 中,只要我保持智能手机选项打开,input range
就不起作用(无论我是否有外观 属性) .
这是我的意思的动画 gif:
首先,我上面描述的 input range
没有出现。它工作正常,我可以移动可滚动的 div
并独立移动 input range
手柄。然后我将 appearance: none
放到 input range
(注意输入范围的格式发生变化),现在我不能再独立于可滚动 div
移动 input range
句柄.最后,从 input range
中删除外观,一切恢复正常(但我的自定义设置消失了)
这是代码,但您只能使用开发者工具在智能手机选项处于活动状态的情况下进行模拟,您可以在其中模拟触摸。
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta charset="UTF-8">
<style>
#outerframe {
height: 310px;
width: 300px;
border: 2px solid red;
padding: 8px;
margin: auto;
overflow: scroll;
}
#scrollarea {
height: 300px;
width: 400px;
border: 1px dashed green;
padding: 16px;
}
input[type=range] {
appearance: none;
background: linear-gradient(90deg, #aaa, #ccf1ff 30%, #ccf1ff 70%, #aaa);
outline: none;
opacity: 0.7;
border-radius: 4px;
height: 14px;
width: 200px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset, 0 -5px 4px rgba(0, 0, 0, 0.5) inset;
vertical-align: middle;
margin: 16px;
}
input[type=text] {
width: 50px;
}
</style>
<title>Testing range in scroll</title>
</head>
<body>
<div id="outerframe">
<div id="scrollarea">
<input type="range" id="rangescroll">
<input type="text" value="50">
</div>
</div>
<script>
scrollarea.firstElementChild.addEventListener('input', evt => {
evt.target.nextElementSibling.value = evt.target.value;
})
</script>
</body>
</html>
编辑:
修复:
Oleg Barabanov,建议在移动输入句柄时制作 overflow: hidden
(在 touchstart and removing the class on touchend). While that works I thought about a more elegant solution. I remembered about event.preventDefault() 上为此添加 class 以及它如何允许我们取消浏览器对后续事件的处理. 这个想法是,如果我可以允许一个事件,input
事件并阻止其余事件(浏览器自动完成的滚动事件),那么它就可以工作。
这是我第一次尝试输入范围的附加代码:
document.querySelector('.scrollarea').firstElementChild.addEventListener("touchstart", (evt) =>
document.querySelector('.outerframe').classList.add("overflow-hidden");
evt.preventDefault();
});
它在这里不起作用(这让我感到惊讶,因为我过去曾成功地使用它来停止默认事件)。但是后来我想起来我在研究 JS 事件的时候还有一种方法可以防止默认事件,那就是 return false for the event:
document.querySelector('.scrollarea').firstElementChild.addEventListener("touchstart", (evt) =>
document.querySelector('.outerframe').classList.add("overflow-hidden");
return false;
});
公平地说,那篇文章提到 return false
仅适用于将事件配置为 ontouchstart
等属性的情况。但是我使用了 addEventListener()
方法,它也有效。
希望以后能帮助到更多的人
我不清楚具体原因,但是当您在移动测试视图中时,在开发工具中禁用 #scrollarea
中的 height
和 width
可以解决问题。移动视图中的 #scrollarea
是通过移动参数内的所有内容来处理的。
另外两个避免必须删除参数的解决方案是在 #rangescroll
.
上设置 position=fixed
或 position=absolute
如果这是浏览器支持的问题,您可以尝试在线工具来帮助生成 CSS 支持跨浏览器的代码。
所以我建议你可以去 here
这是生成的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta charset="UTF-8">
<style>
#outerframe {
height: 310px;
width: 300px;
border: 2px solid red;
padding: 8px;
margin: auto;
overflow: scroll;
}
#scrollarea {
height: 300px;
width: 400px;
border: 1px dashed green;
padding: 16px;
}
input[type=range] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: -webkit-gradient(linear, left top, right top, from(#aaa), color-stop(30%, #ccf1ff), color-stop(70%, #ccf1ff), to(#aaa));
background: -o-linear-gradient(left, #aaa, #ccf1ff 30%, #ccf1ff 70%, #aaa);
background: linear-gradient(90deg, #aaa, #ccf1ff 30%, #ccf1ff 70%, #aaa);
outline: none;
opacity: 0.7;
border-radius: 4px;
height: 14px;
width: 200px;
-webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset, 0 -5px 4px rgba(0, 0, 0, 0.5) inset;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset, 0 -5px 4px rgba(0, 0, 0, 0.5) inset;
vertical-align: middle;
margin: 16px;
}
input[type=text] {
width: 50px;
}
</style>
<title>Testing range in scroll</title>
</head>
<body>
<div id="outerframe">
<div id="scrollarea">
<input type="range" id="rangescroll">
<input type="text" value="50">
</div>
</div>
<script>
scrollarea.firstElementChild.addEventListener('input', evt => {
evt.target.nextElementSibling.value = evt.target.value;
})
</script>
</body>
</html>
在移动设备中,您可以通过拖动来上下滚动,也可以左右滚动。如果您只是在 #outerframe
上禁用 overflow-x
,您可以解决您的问题:
#outerframe {
height: 310px;
width: 300px;
border: 2px solid red;
padding: 8px;
margin: auto;
overflow-x: hidden;
}
#scrollarea {
height: 300px;
width: 400px;
border: 1px dashed green;
padding: 16px;
}
input[type=range] {
appearance: none;
background: linear-gradient(90deg, #aaa, #ccf1ff 30%, #ccf1ff 70%, #aaa);
outline: none;
opacity: 0.7;
border-radius: 4px;
height: 14px;
width: 200px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset, 0 -5px 4px rgba(0, 0, 0, 0.5) inset;
vertical-align: middle;
margin: 16px;
}
input[type=text] {
width: 50px;
}
<div id="outerframe">
<div id="scrollarea">
<input type="range" id="rangescroll">
<input type="text" value="50">
</div>
</div>
<script>
scrollarea.firstElementChild.addEventListener('input', evt => {
evt.target.nextElementSibling.value = evt.target.value;
})
</script>
也许这不是最好的解决方案,但它似乎可行。仅使用 touchstart
和 touchend
事件 + css overflow
:
scrollarea.firstElementChild.addEventListener("input", (evt) => {
evt.target.nextElementSibling.value = evt.target.value;
});
scrollarea.firstElementChild.addEventListener("touchstart", (evt) => {
outerframe.classList.add("overflow-hidden");
});
scrollarea.firstElementChild.addEventListener("touchend", (evt) => {
outerframe.classList.remove("overflow-hidden");
});
#outerframe {
height: 310px;
width: 300px;
border: 2px solid red;
padding: 8px;
margin: auto;
overflow: scroll;
}
#scrollarea {
height: 300px;
width: 400px;
border: 1px dashed green;
padding: 16px;
}
input[type=range] {
appearance: none;
background: linear-gradient(90deg, #aaa, #ccf1ff 30%, #ccf1ff 70%, #aaa);
outline: none;
opacity: 0.7;
border-radius: 4px;
height: 14px;
width: 200px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset, 0 -5px 4px rgba(0, 0, 0, 0.5) inset;
vertical-align: middle;
margin: 16px;
}
input[type=text] {
width: 50px;
}
.overflow-hidden {
overflow: hidden !important;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta charset="UTF-8">
<title>Testing range in scroll</title>
</head>
<body>
<div id="outerframe">
<div id="scrollarea">
<input type="range" id="rangescroll">
<input type="text" value="50">
</div>
</div>
</body>
</html>
您可以将 css 属性 touch-action:manipulation;
添加到您的 #outerframe
以在智能手机模式下禁用来自它的触摸事件
编辑:我发现 touch-action:manipulation;
可能无法解决问题,但 touch-action:none
可以,但代价是渲染 overflow:scroll;
在移动设备中无用
第二次编辑:我发现添加 touch-action: pan-x; touch-action: pan-y
而不是 touch-action:none;
仍然不能使您的外部 div 以某种方式滚动
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta charset="UTF-8">
<style>
#outerframe {
height: 310px;
width: 300px;
border: 2px solid red;
padding: 8px;
margin: auto;
overflow: scroll;
touch-action: pan-x;
touch-action: pan-y;
}
#scrollarea {
height: 300px;
width: 400px;
border: 1px dashed green;
padding: 16px;
touch-action: manipulation;
}
input[type=range] {
appearance: none;
background: linear-gradient(90deg, #aaa, #ccf1ff 30%, #ccf1ff 70%, #aaa);
outline: none;
opacity: 0.7;
border-radius: 4px;
height: 14px;
width: 200px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset, 0 -5px 4px rgba(0, 0, 0, 0.5) inset;
vertical-align: middle;
margin: 16px;
}
input[type=text] {
width: 50px;
}
</style>
<title>Testing range in scroll</title>
</head>
<body>
<div id="outerframe">
<div id="scrollarea">
<input type="range" id="rangescroll">
<input type="text" value="50">
</div>
</div>
<script>
scrollarea.firstElementChild.addEventListener('input', evt => {
evt.target.nextElementSibling.value = evt.target.value;
})
</script>
</body>
</html>
我在 div
中有一个 input range
包含在一个比内部 div
小的外部 div
中。最后的结果是我的内层div
水平滚动(因为外层潜水有overflow: scroll
),而input range
是它的子
为了自定义范围,我用 appearance: none
删除了 CSS 中的外观。现在,这就是发生的事情。当我在 Chrome 开发者工具中检查它时(实际上我使用的是 Brave,但我猜它在 Chrome 中与我在 Chromium 中测试的相同,并且是相同的)并且智能手机选项处于活动状态,99% 的时间,如果我尝试移动范围手柄,它会移动整个 div
。现在,如果我禁用智能手机选项,它就可以正常工作。此外,如果我保留智能手机选项并从 CSS 中删除 appearance: none
,它也可以正常工作,但我对范围的自定义会消失。有人知道这是怎么回事吗?
PS.: 在 Firefox 中,只要我保持智能手机选项打开,input range
就不起作用(无论我是否有外观 属性) .
这是我的意思的动画 gif:
首先,我上面描述的 input range
没有出现。它工作正常,我可以移动可滚动的 div
并独立移动 input range
手柄。然后我将 appearance: none
放到 input range
(注意输入范围的格式发生变化),现在我不能再独立于可滚动 div
移动 input range
句柄.最后,从 input range
中删除外观,一切恢复正常(但我的自定义设置消失了)
这是代码,但您只能使用开发者工具在智能手机选项处于活动状态的情况下进行模拟,您可以在其中模拟触摸。
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta charset="UTF-8">
<style>
#outerframe {
height: 310px;
width: 300px;
border: 2px solid red;
padding: 8px;
margin: auto;
overflow: scroll;
}
#scrollarea {
height: 300px;
width: 400px;
border: 1px dashed green;
padding: 16px;
}
input[type=range] {
appearance: none;
background: linear-gradient(90deg, #aaa, #ccf1ff 30%, #ccf1ff 70%, #aaa);
outline: none;
opacity: 0.7;
border-radius: 4px;
height: 14px;
width: 200px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset, 0 -5px 4px rgba(0, 0, 0, 0.5) inset;
vertical-align: middle;
margin: 16px;
}
input[type=text] {
width: 50px;
}
</style>
<title>Testing range in scroll</title>
</head>
<body>
<div id="outerframe">
<div id="scrollarea">
<input type="range" id="rangescroll">
<input type="text" value="50">
</div>
</div>
<script>
scrollarea.firstElementChild.addEventListener('input', evt => {
evt.target.nextElementSibling.value = evt.target.value;
})
</script>
</body>
</html>
编辑: 修复:
Oleg Barabanov,建议在移动输入句柄时制作 overflow: hidden
(在 touchstart and removing the class on touchend). While that works I thought about a more elegant solution. I remembered about event.preventDefault() 上为此添加 class 以及它如何允许我们取消浏览器对后续事件的处理. 这个想法是,如果我可以允许一个事件,input
事件并阻止其余事件(浏览器自动完成的滚动事件),那么它就可以工作。
这是我第一次尝试输入范围的附加代码:
document.querySelector('.scrollarea').firstElementChild.addEventListener("touchstart", (evt) =>
document.querySelector('.outerframe').classList.add("overflow-hidden");
evt.preventDefault();
});
它在这里不起作用(这让我感到惊讶,因为我过去曾成功地使用它来停止默认事件)。但是后来我想起来我在研究 JS 事件的时候还有一种方法可以防止默认事件,那就是 return false for the event:
document.querySelector('.scrollarea').firstElementChild.addEventListener("touchstart", (evt) =>
document.querySelector('.outerframe').classList.add("overflow-hidden");
return false;
});
公平地说,那篇文章提到 return false
仅适用于将事件配置为 ontouchstart
等属性的情况。但是我使用了 addEventListener()
方法,它也有效。
希望以后能帮助到更多的人
我不清楚具体原因,但是当您在移动测试视图中时,在开发工具中禁用 #scrollarea
中的 height
和 width
可以解决问题。移动视图中的 #scrollarea
是通过移动参数内的所有内容来处理的。
另外两个避免必须删除参数的解决方案是在 #rangescroll
.
position=fixed
或 position=absolute
如果这是浏览器支持的问题,您可以尝试在线工具来帮助生成 CSS 支持跨浏览器的代码。 所以我建议你可以去 here
这是生成的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta charset="UTF-8">
<style>
#outerframe {
height: 310px;
width: 300px;
border: 2px solid red;
padding: 8px;
margin: auto;
overflow: scroll;
}
#scrollarea {
height: 300px;
width: 400px;
border: 1px dashed green;
padding: 16px;
}
input[type=range] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: -webkit-gradient(linear, left top, right top, from(#aaa), color-stop(30%, #ccf1ff), color-stop(70%, #ccf1ff), to(#aaa));
background: -o-linear-gradient(left, #aaa, #ccf1ff 30%, #ccf1ff 70%, #aaa);
background: linear-gradient(90deg, #aaa, #ccf1ff 30%, #ccf1ff 70%, #aaa);
outline: none;
opacity: 0.7;
border-radius: 4px;
height: 14px;
width: 200px;
-webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset, 0 -5px 4px rgba(0, 0, 0, 0.5) inset;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset, 0 -5px 4px rgba(0, 0, 0, 0.5) inset;
vertical-align: middle;
margin: 16px;
}
input[type=text] {
width: 50px;
}
</style>
<title>Testing range in scroll</title>
</head>
<body>
<div id="outerframe">
<div id="scrollarea">
<input type="range" id="rangescroll">
<input type="text" value="50">
</div>
</div>
<script>
scrollarea.firstElementChild.addEventListener('input', evt => {
evt.target.nextElementSibling.value = evt.target.value;
})
</script>
</body>
</html>
在移动设备中,您可以通过拖动来上下滚动,也可以左右滚动。如果您只是在 #outerframe
上禁用 overflow-x
,您可以解决您的问题:
#outerframe {
height: 310px;
width: 300px;
border: 2px solid red;
padding: 8px;
margin: auto;
overflow-x: hidden;
}
#scrollarea {
height: 300px;
width: 400px;
border: 1px dashed green;
padding: 16px;
}
input[type=range] {
appearance: none;
background: linear-gradient(90deg, #aaa, #ccf1ff 30%, #ccf1ff 70%, #aaa);
outline: none;
opacity: 0.7;
border-radius: 4px;
height: 14px;
width: 200px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset, 0 -5px 4px rgba(0, 0, 0, 0.5) inset;
vertical-align: middle;
margin: 16px;
}
input[type=text] {
width: 50px;
}
<div id="outerframe">
<div id="scrollarea">
<input type="range" id="rangescroll">
<input type="text" value="50">
</div>
</div>
<script>
scrollarea.firstElementChild.addEventListener('input', evt => {
evt.target.nextElementSibling.value = evt.target.value;
})
</script>
也许这不是最好的解决方案,但它似乎可行。仅使用 touchstart
和 touchend
事件 + css overflow
:
scrollarea.firstElementChild.addEventListener("input", (evt) => {
evt.target.nextElementSibling.value = evt.target.value;
});
scrollarea.firstElementChild.addEventListener("touchstart", (evt) => {
outerframe.classList.add("overflow-hidden");
});
scrollarea.firstElementChild.addEventListener("touchend", (evt) => {
outerframe.classList.remove("overflow-hidden");
});
#outerframe {
height: 310px;
width: 300px;
border: 2px solid red;
padding: 8px;
margin: auto;
overflow: scroll;
}
#scrollarea {
height: 300px;
width: 400px;
border: 1px dashed green;
padding: 16px;
}
input[type=range] {
appearance: none;
background: linear-gradient(90deg, #aaa, #ccf1ff 30%, #ccf1ff 70%, #aaa);
outline: none;
opacity: 0.7;
border-radius: 4px;
height: 14px;
width: 200px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset, 0 -5px 4px rgba(0, 0, 0, 0.5) inset;
vertical-align: middle;
margin: 16px;
}
input[type=text] {
width: 50px;
}
.overflow-hidden {
overflow: hidden !important;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta charset="UTF-8">
<title>Testing range in scroll</title>
</head>
<body>
<div id="outerframe">
<div id="scrollarea">
<input type="range" id="rangescroll">
<input type="text" value="50">
</div>
</div>
</body>
</html>
您可以将 css 属性 touch-action:manipulation;
添加到您的 #outerframe
以在智能手机模式下禁用来自它的触摸事件
编辑:我发现 touch-action:manipulation;
可能无法解决问题,但 touch-action:none
可以,但代价是渲染 overflow:scroll;
在移动设备中无用
第二次编辑:我发现添加 touch-action: pan-x; touch-action: pan-y
而不是 touch-action:none;
仍然不能使您的外部 div 以某种方式滚动
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta charset="UTF-8">
<style>
#outerframe {
height: 310px;
width: 300px;
border: 2px solid red;
padding: 8px;
margin: auto;
overflow: scroll;
touch-action: pan-x;
touch-action: pan-y;
}
#scrollarea {
height: 300px;
width: 400px;
border: 1px dashed green;
padding: 16px;
touch-action: manipulation;
}
input[type=range] {
appearance: none;
background: linear-gradient(90deg, #aaa, #ccf1ff 30%, #ccf1ff 70%, #aaa);
outline: none;
opacity: 0.7;
border-radius: 4px;
height: 14px;
width: 200px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5) inset, 0 -5px 4px rgba(0, 0, 0, 0.5) inset;
vertical-align: middle;
margin: 16px;
}
input[type=text] {
width: 50px;
}
</style>
<title>Testing range in scroll</title>
</head>
<body>
<div id="outerframe">
<div id="scrollarea">
<input type="range" id="rangescroll">
<input type="text" value="50">
</div>
</div>
<script>
scrollarea.firstElementChild.addEventListener('input', evt => {
evt.target.nextElementSibling.value = evt.target.value;
})
</script>
</body>
</html>