英文:
Creating the simplest HTML toggle button?
问题
I want to create the simplest possible HTML toggle button, but I'm having a hard time finding exactly how to do this.
As far as I can see, there is no direct support for toggle button in HTML, the only thing I found is an ARIA attribute "aria-pressed" recommended for that purpose here: link
So, I came up with the following example with just a <button>
with an aria-pressed
attribute which works, in the sense that the JavaScript handler console.log prints out true, then false, then true, etc - that is, it shows toggling, but only of the 'aria-pressed' attribute - the look of the button is not changed at all!
Now, the thing is, when I use a <button>
as below, with no CSS at all, the button inherits some browser styling defaults; in Firefox at least, I can see (slight) changes in button gray color if I hover (mouseover) the button, and yet some more changes if I click the button and hold it pressed.
So, what I'd like for my "simplest" button, is simply to inherit the existing browser default styling for a "pressed" button, and have the button be styled like that for as long as the 'aria-pressed' attribute is true. Preferably, I would not want to write any specific CSS to style the button (as in specific background color, etc.) - all I want is for the button to inherit the browser defaults for a pressed button when rendering a "toggled" button when its 'aria-pressed' attribute is true.
Is there any way to achieve this, and if so, how?
英文:
I want to create the simplest possible HTML toggle button, but I'm having a hard time finding exactly how to do this.
As far as I can see, there is no direct support for toggle button in HTML, the only thing I found is an ARIA attribute "aria-pressed" recommended for that purpose here: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role#toggle_buttons
So, I came up with the following example with just a <button>
with an aria-pressed
attribute which works, in the sense that the JavaScript handler console.log prints out true, then false, then true etc - that is, it shows toggling, but only of the 'aria-pressed' attribute - the look of the button is not changed at all!
Now, the thing is, when I use a <button>
as below, with no CSS at all, the button inherits some browser styling defaults; in Firefox at least, I can see (slight) changes in button gray color if I hover (mouseover) the button, and yet some more changes if I click the button and hold it pressed.
So, what I'd like for my "simplest" button, is simply to inherit the existing browser default styling for a "pressed" button, and have the button be styled like that for as long as the 'aria-pressed' attribute is true. Preferably, I would not want to write any specific CSS to style the button (as in specific background color etc) - all I want is for the button to inherit the browser defaults for a pressed button, when rendering a "toggled" button when its 'aria-pressed' attribute is true.
Is there any way to achieve this, and if so, how?
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<style>
</style>
</head>
<body>
<button type="button" id="btn-my-toggle" aria-pressed="false">Click me, a toggle button</button>
</body>
<script>
function on_my_toggle_btn_click(e) {
//console.log(e, this); // `e` is `click { target: button#btn-my-toggle ... }`; `this` is `<button id="btn-my-toggle"...`
let isPressed_str = this.getAttribute('aria-pressed'); // note, typeof here is String!
let isPressed = (isPressed_str === 'true'); // "cast" to Boolean
isPressed = !(isPressed); // toggle
this.setAttribute('aria-pressed', isPressed);
console.log(this.getAttribute('aria-pressed'));
}
let my_toggle_btn = document.getElementById('btn-my-toggle');
my_toggle_btn.onclick = on_my_toggle_btn_click;
</script>
<html>
<!-- end snippet -->
答案1
得分: 1
一个复选框是创建一个用户可以切换“开”或“关”的交互元素的最简单和语义化的方式。
<input type="checkbox" id="my-toggle">
<label for="my-toggle">切换我</label>
如果您希望它在视觉上呈现为按钮,可以使用CSS进行样式设置。这里是来自Bootstrap CSS框架的一个示例:
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet">
<input type="checkbox" id="my-toggle" class="btn-check">
<label class="btn btn-primary" for="my-toggle">切换我</label>
英文:
A checkbox is the simplest and most semantic way to create a an interactive element that a user can toggle "on" or "off".
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
<input type="checkbox" id="my-toggle">
<label for="my-toggle">toggle me</label>
<!-- end snippet -->
If you want it to visually appear as a button, you can style it with CSS. Here's an example from the Bootstrap CSS framework:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<input type="checkbox" id="my-toggle" class="btn-check">
<label class="btn btn-primary" for="my-toggle">toggle me</label>
<!-- end snippet -->
答案2
得分: 0
这更简单,如果您不想使用复选框(就像这里https://alvarotrigo.com/blog/toggle-switch-css/)
<button type="button" id="btn-my-toggle">点击我,切换</button>
您可以像这样切换aria-pressed:
document.getElementById('btn-my-toggle')
.addEventListener('click', (e) => {
const tgt = e.target.closest('button');
tgt.classList.toggle('pressed');
tgt.setAttribute('aria-pressed', tgt.matches('.pressed'))
});
#btn-my-toggle {
border: 1px solid black;
}
#btn-my-toggle.pressed {
border: 1px solid red;
}
英文:
This is simpler if you do not want to use a checkbox (like here https://alvarotrigo.com/blog/toggle-switch-css/)
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
document.getElementById('btn-my-toggle')
.addEventListener('click', (e) => e.target.closest('button').classList.toggle('pressed'))
<!-- language: lang-css -->
#btn-my-toggle { border: 1px solid black;}
#btn-my-toggle.pressed { border: 1px solid red;}
<!-- language: lang-html -->
<button type="button" id="btn-my-toggle">Click me, a toggle</button>
<!-- end snippet -->
You can toggle the aria-pressed like this:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
document.getElementById('btn-my-toggle')
.addEventListener('click', (e) => {
const tgt = e.target.closest('button');
tgt.classList.toggle('pressed');
tgt.setAttribute('aria-pressed', tgt.matches('.pressed'))
});
<!-- language: lang-css -->
#btn-my-toggle {
border: 1px solid black;
}
#btn-my-toggle.pressed {
border: 1px solid red;
}
<!-- language: lang-html -->
<button type="button" id="btn-my-toggle">Click me, a toggle</button>
<!-- end snippet -->
答案3
得分: -1
以下是翻译好的内容:
考虑到这里的回复后,我猜总结是,我想要的实际上无法实现 - 但当然,有解决方法。
让我稍微具体一些:我已经研究了几十年的UI,但也许正是因为那样,当我寻找“切换按钮”时,我确实寻找看起来像按钮的东西,而且当它切换时,它看起来像一个“持续按下”的按钮。
这就是为什么我在接受我应该为此目的使用复选框时,在心理上遇到困难,即使这是按设计意图:根据@Quentin的评论:
<input type="checkbox">
是为此设计的UI元素。
虽然我接受这一点 - 对我来说,复选框仍然是一个“复选”在一个“框”中,而当切换关闭时,“复选”消失了 - 在我看来,这不是一个“按钮”(从视觉上说)。
此外,我不经常使用HTML,因此,如果 - 就像在这种情况下一样 - 我需要一个“切换按钮”,我宁愿只使用浏览器默认的“切换按钮”并使用它们,而不是考虑是否对我来说可读 { border: 1px solid #0e0a02;}
或不可读(我确实会在这些事情上走神,在这里我宁愿不这样做)。
因此,问题在于,即使我最终接受使用 <input type="checkbox">
- 那么我还是被迫思考自定义样式和 { border: 1px solid #0e0a02;}
(参见 https://stackoverflow.com/questions/15436450/style-checkboxes-as-toggle-buttons ),而我本来想避免这种情况。
退一步说,我知道当按钮只是坐在那里时,浏览器有渲染 <button>
的样式默认值 - 然后还有一个悬停时按钮的样式(鼠标悬停),以及按钮按下时的样式(并保持按住)。
因此,如果我可以说:“在切换属性为true的情况下,将此按钮呈现为'按下'”,那就没问题 - 我不必编写自定义CSS,而且我将继承默认的浏览器样式。但我能说吗?
显然不行:
https://stackoverflow.com/questions/6238314/any-way-to-keep-an-html-button-pressed
有没有办法让它在视觉上保持按下并通过javascript取消按下
没有办法用javascript做到这一点。
但您可以使用javascript模拟这种效果,通过添加/删除css类,或直接编辑您选择使用的css属性。
因此,我想,如果我只能获取浏览器对 <button>:active
(按下时的伪样式)的CSS样式,然后将其用作“基本CSS”类来“继承”,那就太好了 - 但是:
https://stackoverflow.com/questions/43092537/is-it-possible-to-inherit-css-class
不行。
CSS继承是从父元素到子元素的,而不是从一个规则集到另一个规则集。
这个方法也行不通;最后,我回到了 https://stackoverflow.com/questions/6238314 的被接受答案:
我有一个按钮... 有没有办法让它在视觉上保持按下并通过javascript取消按下?
我会尝试使用CSS,并使用border-style inset,个人认为。
现在,border-style: inset
不是浏览器(至少是火狐)呈现 <button>
的 :active
(即 <button>
按下)的方式 - 但这是我能够做到的最低限度,而不必担心手动通过CSS样式化按钮的 其余 部分,并继承浏览器默认的任何东西。
所以,我可以使用 https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role 中的方法,并为 aria-pressed
属性添加一个CSS规则 - 我还将 role
更改为我的自定义 "togglebutton";通过这样做,我有了:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<style>
[role="togglebutton"][aria-pressed="true"] {
border-style: inset;
border-radius: 4px;
}
</style>
</head>
<body>
<button type="button" id="btn-my-toggle" role="togglebutton" aria-pressed="false">Click me, a toggle button</button>
</body>
<script>
function on_my_toggle_btn_click(e) {
//console.log(e, this); // `e` is `click { target: button#btn-my-toggle ... }`; `this` is `<button id="btn-my-toggle"...`
let isPressed_str = this.getAttribute('aria-pressed'); // note, typeof here is String!
let isPressed = (isPressed_str === 'true'); // "cast" to Boolean
isPressed = !(isPressed); // toggle
this.setAttribute('aria-pressed', isPressed);
//console.log(this.getAttribute('aria-pressed'));
}
let my_toggle_btn = document.getElementById('btn-my-toggle');
my_toggle_btn.onclick = on_my_toggle_btn_click;
</script>
<html>
...现在我有了一个切换按钮,从语义上来说是一个 <button>
,在很大程度上继承了此元素的浏览器样式默认值,而无需手动通过CSS样式化(除了 border-style: inset;
和 border-radius
以使其看起来与Firefox的默认按钮显示相同)。
英文:
After considering the responses here, I guess the summary is, that what I want cannot really be achieved - but of course, there are workarounds.
Let me be slightly more specific: it's been some decades since I've studied UI, but maybe as a consequence of that, when I look for a "toggle button", I indeed look for something that looks like a button, and when its toggled, it looks like a "constantly pressed" button.
That is why I have a mental difficulty in accepting that I should use a checkbox for this purpose, even if it is intended by design: as per comment by @Quentin:
> <input type="checkbox">
is the UI element designed for this.
While I do accept that -- for me, a check box is still a "check" in a "box", and when toggled off, the "check" disappears - and in my mind, this is not a "button" (visually speaking).
Furthermore, I do not use HTML often, and so, if - as in this case, - I need a "toggle button", I would prefer just to grab whatever the browser defaults are for "toggle button" and work with those, instead of thinking whether { border: 1px solid #0e0a02;}
is readable for me or not (and I indeed can get sidetracked in these things, and here I'd prefer I do not).
So, the problem here is that even if I end up accept having to use <input type="checkbox">
- then I'm forced to thing about custom styling and { border: 1px solid #0e0a02;}
( see e.g. https://stackoverflow.com/questions/15436450/style-checkboxes-as-toggle-buttons ) which I wanted to avoid in the first place.
Taking a step back: I know that the browser has style defaults for rendering a <button>
when it just sits there - then also a style for when the button is hovered (mouse-over'ed), and a style for when the button is pressed (and held).
So, if I could say: "have this button rendered as 'pressed', in case the toggled attribute is true", I'm all set - I don't have to write custom CSS, and I'd have inherited the default browser styling. But can I say that?
Apparently not:
https://stackoverflow.com/questions/6238314/any-way-to-keep-an-html-button-pressed
>> Is there any way to keep it visually pressed and unpress it via javascript
>
> There is no way to do that with javascript.
>
> But you can use javascript to simulate that effect by adding/removing a css class, or directly editing the css properties you have chosen to use.
So, I thought, if I could just get to whatever CSS styles the browser has for <button>:active
(the pseudo-style when pressed), and used that as a "base CSS" class to "inherit" from, that would be good - but:
https://stackoverflow.com/questions/43092537/is-it-possible-to-inherit-css-class
> No.
>
> CSS inheritance is from parent element to child element, not from one ruleset to another.
There goes that approach too; and finally, I went back to the accepted answer of https://stackoverflow.com/questions/6238314 :
>> I have a button ... Is there any way to keep it visually pressed and unpress it via javascript?
>
> I would try CSS and use the border-style inset, personally.
Now, border-style: inset
is NOT how the browser (at least firefox) renders <button>
's :active
(that is, <button>
pressed) - but it's the bare minimum I can have, without having to worry about CSS styling the rest of the button, and inheriting whatever the browser defaults are.
So then, I can just use the approach in https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role and add a CSS rule for the aria-pressed
attribute - and I also changed the role
to my own custom "togglebutton"; and with that, I have:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<style>
[role="togglebutton"][aria-pressed="true"] {
border-style:inset;
border-radius:4px;
}
</style>
</head>
<body>
<button type="button" id="btn-my-toggle" role="togglebutton" aria-pressed="false">Click me, a toggle button</button>
</body>
<script>
function on_my_toggle_btn_click(e) {
//console.log(e, this); // `e` is `click { target: button#btn-my-toggle ... }`; `this` is `<button id="btn-my-toggle"...`
let isPressed_str = this.getAttribute('aria-pressed'); // note, typeof here is String!
let isPressed = (isPressed_str === 'true'); // "cast" to Boolean
isPressed = !(isPressed); // toggle
this.setAttribute('aria-pressed', isPressed);
//console.log(this.getAttribute('aria-pressed'));
}
let my_toggle_btn = document.getElementById('btn-my-toggle');
my_toggle_btn.onclick = on_my_toggle_btn_click;
</script>
<html>
<!-- end snippet -->
... and now I have a toggle button, which is semantically a <button>
, and which for the most part inherits the browser styling defaults for this element, and I did not have to style manually via CSS (beyond the border-style:inset;
, and also the border-radius
to make it look the same as the default button display of Firefox).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论