How do I properly structure a dark mode toggle using Javascript? - javascript

I've been trying to have my toggle trigger a dark mode on and off using JavaScript but clearly I'm doing something wrong. I attempted to trigger it by applying the light class to my body and using addClassListener. Below is a simplified version of my code but i also plan on doing this on specific classes as well in order to change font and div colors in each different mode as well. Any suggestions?
HTML
<label class="switch">
<input type="checkbox" checked>
<span id="slide" class="slider round"></span>
</label>
CSS
body{
position: absolute;
top: 320px;
left: 0;
width: 100%;
height: 100%;
background-color: hsl(230, 17%, 14%);
z-index: -1;
}
body.light {
background-color: white;
}
Javascript
const checkbox = document.getElementById('slide');
checkbox.addEventListener('change', ()
==>{document.body.classList.toggle('light');
});

You are attempting to get the element by id, but you have not defined any ids in your snippet.
<label class="switch">
<input type="checkbox" checked>
<span id="slider" class="slider round"></span>
</label>
Additionally, you're listening for a change event on a span element. The span element will never fire a change event. If you change that to listen in the input element, it should fire. Documentation

Related

Make DIV take space of another DIV which is hidden

I am building a quiz that is going to generate a set of 10 questions of out a pool of 40.
My idea is to use a generated array of 10 numbers and hide them using JQuery. The JQuery would .hide() the questions that aren't needed and the would be displayed in the default format.
I need the divs of the questions that are selected to take up the spaces left by the hidden divs. Since the pool is massive, is there a practical way to do this?
Note: I don't have the JQuery done at the moment.
/* Quiz Styling */
.quiz-wrapper{
position: absolute;
top: 90%;
left: 50%;
transform: translate(-50%, -50%);
width: 50%;
}
.header{
margin-top: 50px;
height: 150px;
text-align: center;
background-color: red;
width: 100%;
}
.question{
margin-top: 10px;
}
ul{
margin-left: 10px;
list-style-type: none;
}
#qu1{
visibility: hidden;
}
<div class="header">
<h1> You have made it into the quiz!</h1>
<br>
<p>You are about to go through a series of 10 MCQs. <br>
At the end of the questions, you will obtain your marks!<br>
Good Luck and Have Fun! <br>
Once ready, press the button below!</p>
</div>
<div class="quiz-wrapper">
<button id="quiz_start" class="quiz_start">Click me to start!</button>
<div class="quiz">
<div class="question" id="qu1"><span class="qu_no"></span>A game where player fight in an arena-style environment is referred as __________?
<ul>
<li>
<input type="radio" id="one_a" name="gametype" value="one_a" required>
<label for="one_a">MMO</label>
</li>
<li>
<input type="radio" id="one_b" name="gametype" value="one_b" required>
<label for="one_b">RPG</label>
</li>
<li>
<input type="radio" id="one_c" name="gametype" value="one_c" required>
<label for="one_c">Open World</label>
</li>
<li>
<input type="radio" id="one_d" name="gametype" value="one_d" required>
<label for="one_d">FPS</label>
</li>
</ul>
</div>
<div class="question" id="qu2"><span class="qu_no"></span>What is the name of the most recent graphics card series released by nVidia?
<ul>
<li>
<input type="radio" id="two_a" name="gpucards" value="two_a" required>
<label for="two_a">RTX 3000 Series</label>
</li>
<li>
<input type="radio" id="two_b" name="gpucards" value="two_b" required>
<label for="two_b">Intel i5</label>
</li>
<li>
<input type="radio" id="two_c" name="gpucards" value="two_c" required>
<label for="two_c">Jolt Series</label>
</li>
<li>
<input type="radio" id="two_d" name="gpucards" value="two_d" required>
<label for="two_d">GTX 1000 Series</label>
</li>
</ul>
</div>
I think that if any element have been hidden by JQuery .hide(), the element has display: none style, so nothing in this element cannot be displayed.
Simply have a set size for the whole div.
The hidden questions will have display:none and will therefore not take up any space, you can give all questions something like height: 100%; and they will always fill out the big div, or if they also have a set size (as in set by pixels, or vh etc.) the questions will just keep appearing as in a list.
Not sure if this answers your question or if there is something else you are trying to do, do you mean that you always want the next question on top? In that case I would not have the questions as a part of the div from the beginning, but rather have them in an array in JavaScript and then use the jquery function .prepend() to add them as the first element to the div.

html id and class for js and css in same component not working

I am enabling and disabling a div by checking two radio button (yes and no) but I am facing an issue when I am putting both id and class in same div and when I am using two div (one for id as parent and another for class as child) then its working fine.
function check1() {
if (document.getElementById("isOutsourcing_yes").checked) {
document.getElementById("s1").hidden = false;
}
if (document.getElementById("isOutsourcing_no").checked) {
document.getElementById("s1").hidden = true;
}
}
.padd_left {
display: inline-block;
padding-left: 40px;
}
<input type="radio" name="isOutsourcing" id="isOutsourcing_yes" onchange="check1()" checked> Yes
<input type="radio" name="isOutsourcing" id="isOutsourcing_no" onchange="check1()"> No
<div id="s1" class="padd_left">
<h1>Hello..</h1>
</div>
above code is not working but when I am replacing last div as below then it's working fine
<div class="padd_left">
<div id="s1">
<h1>Hello..</h1>
</div>
</div>
Inline blocks aren't a big fan of hidden. Try this instead
document.getElementById("s1").style.visibility = "hidden"; // or visible
Also note the difference between the display property and the visibility property. You could set it to display: none if you wanted it to completely disappear from the page without a trace (besides in the source). visibility: hidden will have it take up the same space but not render anything. Depending on how you want your page to look, you'll have to make that decision.
https://www.w3schools.com/jsref/prop_style_visibility.asp
https://www.w3schools.com/cssref/pr_class_display.asp
Here is the more simple solution using only pure CSS and HTML, without javascript
.padd_left {
display: inline-block;
padding-left: 40px;
}
#isOutsourcing_no:checked + #s1 h1{
display: none;
}
<input type="radio" name="isOutsourcing" id="isOutsourcing_yes" checked> Yes
<input type="radio" name="isOutsourcing" id="isOutsourcing_no"> No
<div id="s1" class="padd_left">
<h1>Hello..</h1>
</div>

How to use 3 radio button and relate those button to different styling for div tag?

I have created a div tag and wrote some content in it. and have created 3 types of styling effect for that div tag. so have created 3 radio buttons and now i dont know how to connect these things together. If check one of the radio button the div tag should take one of the styling.
Thanks in Advance.
You could do it with css only.
input[value="blue"]:checked ~ div {
background: blue;
}
input[value="yellow"]:checked ~ div {
background: yellow;
}
input[value="orange"]:checked ~ div {
background: orange;
}
div {
width: 80px;
height: 80px;
}
<label for="blue">blue</label>
<input type="radio" value="blue" id="blue" name="group1">
<label for="yellow">yellow</label>
<input type="radio" value="yellow" id="yellow" name="group1">
<label for="orange">orange</label>
<input type="radio" value="orange" id="orange" name="group1">
<div></div>

How to style radio buttons differently if they fit in a single row?

PLAYGROUND HERE
I'd like to style radio buttons differently if they fit in a single row. For example:
The first container doesn't have enough space to fit all the radio buttons in a single row. Therefore, they appear vertically as normal radio buttons.
The second container has enough space. Therefore, the radio buttons appear as buttons.
Is that possible to achieve this behaviour using CSS only?
If not, Javascript "hack" is welcome.
PLAYGROUND HERE
HTML
<div class="container radio">
<div>
<input id="a1" type="radio" name="radio">
<label for="a1">Yes,</label>
</div>
<div>
<input id="a2" type="radio" name="radio">
<label for="a2">it</label>
</div>
<div>
<input id="a3" type="radio" name="radio">
<label for="a3">is</label>
</div>
<div>
<input id="a4" type="radio" name="radio">
<label for="a4">possible</label>
</div>
<div>
<input id="a5" type="radio" name="radio">
<label for="a5">to</label>
</div>
<div>
<input id="a6" type="radio" name="radio">
<label for="a6">achieve</label>
</div>
<div>
<input id="a7" type="radio" name="radio">
<label for="a7">this</label>
</div>
</div>
<div class="container buttons">
<div>
<input id="b1" type="radio" name="buttons">
<label for="b1">Yes,</label>
</div>
<div>
<input id="b2" type="radio" name="buttons">
<label for="b2">it</label>
</div>
<div>
<input id="b3" type="radio" name="buttons">
<label for="b3">is</label>
</div>
<div>
<input id="b4" type="radio" name="buttons">
<label for="b4">possible</label>
</div>
</div>
CSS (LESS)
.container {
display: flex;
width: 220px;
padding: 20px;
margin-top: 20px;
border: 1px solid black;
&.radio {
flex-direction: column;
}
&.buttons {
flex-direction: row;
> div {
input {
display: none;
&:checked + label {
background-color: #ADFFFE;
}
}
label {
padding: 5px 10px;
margin: 0 1px;
background-color: #ccc;
}
}
}
}
Not possible in CSS, but it doesn't take much JavaScript.
In CSS, add flex-shrink: 0 to > div. This will prevent .container's children from shrinking smaller than their extent.
In JavaScript:
Apply the buttons class.
Use Element.getBoundingClientRect to determine if the last child of .container is outside the extent of .container. If so, switch to the radio class. (You also need to take the right padding into account. Thanks to #Moob for pointing that out.)
Javascript
var container = document.querySelector('.container'),
lastChild= document.querySelector('.container > :last-child'),
paddingRight= parseInt(window.getComputedStyle(container, null).getPropertyValue('padding-right')),
timer;
window.onresize = function() {
clearTimeout(timer);
timer= setTimeout(function() {
container.classList.remove('radio');
container.classList.add('buttons');
if (container.getBoundingClientRect().right-paddingRight <
lastChild.getBoundingClientRect().right) {
container.classList.add('radio');
container.classList.remove('buttons');
}
});
}
Updated JSBin
I can't think of a CSS only solution but you could use JS to test if the items would fit in a row and apply the 'radio' or 'buttons' classname accordingly:
Forgive my rough JS - its inelegant and for modern browsers only but you get the idea:
var containers = document.querySelectorAll(".container"),
test = function(){
for (i = 0; i < containers.length; ++i) {
var container = containers[i],
divs = container.querySelectorAll("div"),
iw = 0;
container.classList.remove("radio");
container.classList.add("buttons");
//get the sum width of the div
for (d = 0; d < divs.length; ++d) {
iw+=divs[d].offsetWidth;
}
var style = window.getComputedStyle(container, null);
var ow = parseInt(style.getPropertyValue("width"));
if(ow<=iw){
container.classList.add("radio");
container.classList.remove("buttons");
}
}
};
window.onresize = function(event) {
test();
};
test();
http://jsbin.com/zofixakama/3/edit?html,css,js,output
(resize the window / panel to see the effect)
Update: If you add .container div {flex-shrink:0;} to the style the JS can be much simpler as we don't have to measure the combined width of the divs (thanks #rick-hitchcock). However, although the code is more elegant, it does not take the container's padding into account.
See: http://jsbin.com/zofixakama/5/edit?html,css,js,output
If I understand what you're asking correctly, you can change your flex-direction portion to row instead of column. This will cause them to align inside the box.
You'll have to do some more styling to properly get the labels to appear the way you want, but this should put them in the row for you. I've updated the playground with my changes.
Try the following example..............
------------HTML-----------
<html>
<head>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
<div class="table-row">
<div class="col">
<input type="Radio">This
</div>
<div class="col" style="padding-top: 2px;">
<input type="Radio">Is
</div>
<div class="col">
<input type="Radio">Simply
</div>
<div class="col" style="padding-top: 2px;">
<input type="Radio">Possible
</div>
</div>
</body>
</html>
-------CSS-------------
.table-row{
display:table-row;
/* text-align: center; */
}
.col{
display:table-cell;
/* border: 1px solid #CCC; */
}
Wouldn't it work to test for width then if necessary remove the radio button icon and replace with a graphic or shape?
.checkbox {
display:none;
}
.label {
display: inline-block;
height: 20px;
background: url('picture.png');
}
It's probably not that simple but I use that for check boxes and it seems to work in that situation.
You can achieve this only by using css and no need of scripting.
HTML: You have to place the input within tag which will contain the text.
<div>
<label for="a1">
<input id="a1" type="radio" name="radio">Yes,
</label> </div>
CSS: Here in CSS we will have to hide the radio button, so that only the text will be visible. When the user clicks on the text, it actually clicks the radio button.
div lable input#a1{
display:none;
}
there is pretty solution CSS only, but you have to know maximum amount of elements in row. It is based on counter, but not on real size.
For example, if you are sure, that you can put 4 elements into a row, in any case, you may use following selector:
if amount is more less or equal 4:
div:nth-last-child(-n+5):first-child,
div:nth-last-child(-n+5):first-child ~ div {
}
if amount is more then 4:
div:nth-last-child(n+5),
div:nth-last-child(n+5) ~ div {
}
try this: http://jsbin.com/fozeromezi/2/edit (just remove/add divs)

Forcing a tab stop on a hidden element? Possible?

The site is here
I have opt to using the radiobutton's labels as customized buttons for them. This means the radio inputs themselves are display:none. Because of this, the browsers don't tab stop at the radio labels, but I want them to.
I tried forcing a tabindex to them, but no cigar.
I have came up with just putting a pointless checkbox right before the labels, and set it to width: 1px; and height 1px; which seems to only really work on chrome & safari.
So do you have any other ideas for forcing a tab stop at those locations without showing an element?
Edit:
Just incase someone else comes by this, this is how I was able to insert small checkboxes into chrome & safari using JQuery:
if ($.browser.safari) {
$("label[for='Unlimited']").parent().after('<input style="height:1px; width:1px;" type="checkbox">');
$("label[for='cash']").parent().after('<input style="height:1px; width:1px;" type="checkbox">');
$("label[for='Length12']").parent().after('<input style="height:1px; width:1px;" type="checkbox">');
}
Note: $.browser.webkit was not becoming true...so I had to use safari
a working solution in my case to enable tab selection / arrow navigation was to set the opacity to zero rather than a "display: none"
.styled-selection input {
opacity: 0; // hide it visually
z-index: -1; // avoid unintended clicks
position: absolute; // don't affect other elements positioning
}
Keep the radio input hidden, but set tabindex="0" on the <label> element of reach radio input.
(A tab index of 0 keeps the element in tab flow with other elements with an unspecified tab index which are still tabbable.)
If you separate the label from any field and set a tabIndex you can tab to it and capture mouse and key events. It seems more sensible to use buttons or inputs with type="button",
but suit yourself.
<form>
<fieldset>
<input value="today">
<label tabIndex="0" onfocus="alert('label');">Label 1</label>
</fieldset>
</form>
I have an alternative answer that I think has not been mentioned yet. For recent work I've been reading the Mozilla Developer Docs MDN Docs, Forms, especially the Accessibility Section MDN Docs, Accessible HTML(5), for information related to keyboard accessibility and form structure.
One of the specific mentions in the Accessibility section is to use HTML5 elements when and where possible -- they often have cross-browser and more accessible support by default (not always true, but clear content structure and proper elements also help screen reading along with keyboard accessibility).
Anyway, here's a JSFiddle: JSFiddle::Keyboard Accessible Forms
Essentially, what I did was:
shamelessly copy over some of the source code from a Mozilla source code to a JSFiddle (source in the comments of the fiddle)
create a TEXT-type and assign it the "readonly" HTML5 attribute
add attribute tabindex="0" to the readonly
Modify the "readonly" CSS for that input element so it looks "blank" or hidden"
HTML
<title>Native keyboard accessibility</title>
<body>
<h1>Native keyboard accessibility</h1>
<hr>
<h2>Links</h2>
<p>This is a link to Mozilla.</p>
<p>Another link, to the Mozilla Developer Network.</p>
<h2>Buttons</h2>
<p>
<button data-message="This is from the first button">Click me!</button>
<button data-message="This is from the second button">Click me too!
</button>
<button data-message="This is from the third button">And me!</button>
</p>
<!-- "Invisible" HTML(5) element -->
<!-- * a READONLY text-input with modified CSS... -->
<hr>
<label for="hidden-anchor">Hidden Anchor Point</label>
<input type="text" class="hidden-anchor" id="hidden-anchor" tabindex="0" readonly />
<hr>
<h2>Form</h2>
<form name="personal-info">
<fieldset>
<legend>Personal Info</legend>
<div>
<label for="name">Fill in your name:</label>
<input type="text" id="name" name="name">
</div>
<div>
<label for="age">Enter your age:</label>
<input type="text" id="age" name="age">
</div>
<div>
<label for="mood">Choose your mood:</label>
<select id="mood" name="mood">
<option>Happy</option>
<option>Sad</option>
<option>Angry</option>
<option>Worried</option>
</select>
</div>
</fieldset>
</form>
<script>
var buttons = document.querySelectorAll('button');
for(var i = 0; i < buttons.length; i++) {
addHandler(buttons[i]);
}
function addHandler(button) {
button.addEventListener('click', function(e) {
var message = e.target.getAttribute('data-message');
alert(message);
})
}
</script>
</body>
CSS Styling
input {
margin-bottom: 10px;
}
button {
margin-right: 10px;
}
a:hover, input:hover, button:hover, select:hover,
a:focus, input:focus, button:focus, select:focus {
font-weight: bold;
}
.hidden-anchor {
border: none;
background: transparent!important;
}
.hidden-anchor:focus {
border: 1px solid #f6b73c;
}
BTW, you can edit the CSS rule for .hidden-anchor:focus to remove the highlight for the hidden anchor if you want. I added it just to "prove" the concept here, but it still works invisibly as requested.
I hope this helps!
My preference:
.tab-only:not(:focus) {
position: fixed;
left: -999999px;
}
<button class="tab-only">Jump to main</button>
Another great option would be to nest your input + div in a label and hide the input by setting width and height to 0px instead of display: none
This method even allows you to use pseudo-classes like :focus or :checked by using input:pseudo + styleDiv
<label>
<input type="radio">
<div class="styleDiv">Display text</div>
</label>
input
{
width: 0px;
height: 0px;
}
input + .styleDiv
{
//Radiobutton style here
display: inline-block
}
input:checked + .styleDiv
{
//Checked style here
}
Discard the radio-buttons and instead; keep some hidden fields in your code, in which you store the selected value of your UI components.

Categories

Resources