创建最简单的HTML切换按钮?

huangapple go评论78阅读模式
英文:

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 &lt;button&gt; 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 &lt;button&gt; 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 -->

&lt;!DOCTYPE html&gt;
&lt;html&gt;

&lt;head&gt;
  &lt;title&gt;test&lt;/title&gt;
  &lt;style&gt;

  &lt;/style&gt;
&lt;/head&gt;

&lt;body&gt;
  &lt;button type=&quot;button&quot; id=&quot;btn-my-toggle&quot; aria-pressed=&quot;false&quot;&gt;Click me, a toggle button&lt;/button&gt;
&lt;/body&gt;

&lt;script&gt;
  function on_my_toggle_btn_click(e) {
    //console.log(e, this); // `e` is `click { target: button#btn-my-toggle ... }`;  `this` is `&lt;button id=&quot;btn-my-toggle&quot;...`
    let isPressed_str = this.getAttribute(&#39;aria-pressed&#39;); // note, typeof here is String!
    let isPressed = (isPressed_str === &#39;true&#39;); // &quot;cast&quot; to Boolean
    isPressed = !(isPressed); // toggle
    this.setAttribute(&#39;aria-pressed&#39;, isPressed);
    console.log(this.getAttribute(&#39;aria-pressed&#39;));
  }

  let my_toggle_btn = document.getElementById(&#39;btn-my-toggle&#39;);
  my_toggle_btn.onclick = on_my_toggle_btn_click;
&lt;/script&gt;

&lt;html&gt;

<!-- 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 -->

&lt;input type=&quot;checkbox&quot; id=&quot;my-toggle&quot;&gt;
&lt;label for=&quot;my-toggle&quot;&gt;toggle me&lt;/label&gt;

<!-- 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 -->

&lt;link href=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css&quot; rel=&quot;stylesheet&quot;/&gt;
&lt;input type=&quot;checkbox&quot; id=&quot;my-toggle&quot; class=&quot;btn-check&quot;&gt;
&lt;label class=&quot;btn btn-primary&quot; for=&quot;my-toggle&quot;&gt;toggle me&lt;/label&gt;

<!-- 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(&#39;btn-my-toggle&#39;)

.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 -->

&lt;button type=&quot;button&quot; id=&quot;btn-my-toggle&quot;&gt;Click me, a toggle&lt;/button&gt;

<!-- end snippet -->

You can toggle the aria-pressed like this:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

document.getElementById(&#39;btn-my-toggle&#39;)
  .addEventListener(&#39;click&#39;, (e) =&gt; {
    const tgt = e.target.closest(&#39;button&#39;);
    tgt.classList.toggle(&#39;pressed&#39;);
    tgt.setAttribute(&#39;aria-pressed&#39;, tgt.matches(&#39;.pressed&#39;))
  });

<!-- language: lang-css -->

#btn-my-toggle {
  border: 1px solid black;
}

#btn-my-toggle.pressed {
  border: 1px solid red;
}

<!-- language: lang-html -->

&lt;button type=&quot;button&quot; id=&quot;btn-my-toggle&quot;&gt;Click me, a toggle&lt;/button&gt;

<!-- 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:

> &lt;input type=&quot;checkbox&quot;&gt; 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 &lt;input type=&quot;checkbox&quot;&gt; - 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 &lt;button&gt; 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 &lt;button&gt;: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 &lt;button&gt;'s :active (that is, &lt;button&gt; 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 -->

&lt;!DOCTYPE html&gt;
&lt;html&gt;

&lt;head&gt;
  &lt;title&gt;test&lt;/title&gt;
  &lt;style&gt;
[role=&quot;togglebutton&quot;][aria-pressed=&quot;true&quot;] {
  border-style:inset;
  border-radius:4px;
}
  &lt;/style&gt;
&lt;/head&gt;

&lt;body&gt;
  &lt;button type=&quot;button&quot; id=&quot;btn-my-toggle&quot; role=&quot;togglebutton&quot; aria-pressed=&quot;false&quot;&gt;Click me, a toggle button&lt;/button&gt;
&lt;/body&gt;

&lt;script&gt;
function on_my_toggle_btn_click(e) {
  //console.log(e, this); // `e` is `click { target: button#btn-my-toggle ... }`;  `this` is `&lt;button id=&quot;btn-my-toggle&quot;...`
  let isPressed_str = this.getAttribute(&#39;aria-pressed&#39;); // note, typeof here is String!
  let isPressed = (isPressed_str === &#39;true&#39;); // &quot;cast&quot; to Boolean
  isPressed = !(isPressed); // toggle
  this.setAttribute(&#39;aria-pressed&#39;, isPressed);
  //console.log(this.getAttribute(&#39;aria-pressed&#39;));
}

let my_toggle_btn = document.getElementById(&#39;btn-my-toggle&#39;);
my_toggle_btn.onclick = on_my_toggle_btn_click;
&lt;/script&gt;

&lt;html&gt;

<!-- end snippet -->

... and now I have a toggle button, which is semantically a &lt;button&gt;, 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).

huangapple
  • 本文由 发表于 2023年8月4日 22:54:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76837048.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定