Can an element be hidden and shown without Javascript? - html

I'm working on an app where I am using the DOMTokenList for shown and hidden an element using add() and remove() methods but the code is getting big. Example:
button.addEventListener("click", () => {
elem1.classList.add("display-none");
elem2.classList.remove("display-none");
elem3.classList.remove("display-none");
elem4.classList.add("display-none");
});
button2.addEventListener("click", () => {
elem1.classList.remove("display-none");
elem2.classList.add("display-none");
elem3.classList.add("display-none");
elem4.classList.remove("display-none");
});
I've seven code parts similar to the example and I started looking others ways but I tried with CSS
.box {
--displayRed: block;
--displayGreen: none;
--displayBlue: none;
height: 100px;
width: 100px;
}
.box--red {
display: var(--displayRed);
background-color: #ff0000;
}
.box--green {
display: var(--displayGreen);
background-color: #00ff00;
}
.box--blue {
display: var(--displayBlue);
background-color: #0000ff;
}
.box--red:target {
--displayRed: block;
--displayGreen: none;
--displayBlue: none;
}
.box--green:target {
--displayRed: none;
--displayGreen: block;
--displayBlue: none;
}
.box--blue:target {
--displayRed: none;
--displayGreen: none;
--displayBlue: block;
}
<div>
<div class="box">
<div id="boxRed" class="box box--red"></div>
<div id="boxGreen" class="box box--green"></div>
<div id="boxBlue" class="box box--blue"></div>
</div>
<nav>
<ul>
<li>Show red box</li>
<li>Show green box</li>
<li>Show blue box</li>
</ul>
</nav>
</div>
I was expecting the red box to hide when I clicked the link to show the yellow box but it only scrolled down and didn't hide the red box. I tried to find others solution with videos, Pseudo-classes, Selectors, even with two question that are Can text be hidden and shown using just CSS (no JavaScript code)? [closed] and Ocultar y Mostrar un elemento css but I can't find the perfect idea. I ACCEPT SUGGESTIONS

Since your goal is to hide the elements with display:none, I'll assume the DOM order doesn't matter.
So what you can do with no JS is to place your default element at the end of the container and then hide it when it's following a :targeted element:
.box {
--displayRed: block;
--displayGreen: none;
--displayBlue: none;
height: 100px;
width: 100px;
}
.box--red {
display: var(--displayRed);
background-color: #ff0000;
}
.box--green {
display: var(--displayGreen);
background-color: #00ff00;
}
.box--blue {
display: var(--displayBlue);
background-color: #0000ff;
}
:target ~ .box--red { /* when any other than red is selected */
--displayRed: none;
}
.box--green:target {
--displayRed: none;
--displayGreen: block;
--displayBlue: none;
}
.box--blue:target {
--displayRed: none;
--displayGreen: none;
--displayBlue: block;
}
<div>
<div class="box">
<div id="boxGreen" class="box box--green"></div>
<div id="boxBlue" class="box box--blue"></div>
<!-- move the default one last -->
<div id="boxRed" class="box box--red"></div>
</div>
<nav>
<ul>
<li>Show red box</li>
<li>Show green box</li>
<li>Show blue box</li>
</ul>
</nav>
</div>
Ps: as noted by T.J Crowder in the comments below, the css-variables in here are quite useless as they won't actually reach the elements they're supposed to affect.
So you could rewrite all this without these variables and simply do:
.box {
height: 100px;
width: 100px;
}
/* might be better to remove the "box" class on the container but... */
.box[id] {
display: none;
}
.box:target ~ .box--red {
display: none;
}
.box:target {
display: block;
}
/* This one is the default one */
.box.box--red {
background-color: #ff0000;
display: block;
}
/* only the color needs to be defined for the others */
.box--green {
background-color: #00ff00;
}
.box--blue {
background-color: #0000ff;
}
<div>
<div class="box">
<div id="boxGreen" class="box box--green"></div>
<div id="boxBlue" class="box box--blue"></div>
<!-- move the default one last -->
<div id="boxRed" class="box box--red"></div>
</div>
<nav>
<ul>
<li>Show red box</li>
<li>Show green box</li>
<li>Show blue box</li>
</ul>
</nav>
</div>

The trick is defaulting to the red box when there's no hash fragment. I'm not sure you can do that with a pure CSS solution. (Edit: it turns out you can, as shown by Kaiido, provided you can put the default at the end; I should have thought of the general sibling combinator! But the CSS custom properties [aka "variables"] aren't actually doing anything in that AFAICS, see this fiddle.)
I don't know if it's possible to do this with CSS custom properties (aka "variables"); I tend to think not, since setting a custom property in the selector rule for one sibling (say, .box--blue:target) doesn't change its value for any elements not inside that .box--blue element (doesn't change it for the .box--red sibling, for instance). (Fiddle.) But you can definitely show/hide boxes with the old checkbox/radio button trick:
Define the boxes as display: none.
Have invisible radio buttons immediately prior to the box the radio button will relate to in the same parent:
<input type="radio" name="box-controller" id="chk-box--red" checked>
<div id="boxRed" class="box box--red"></div>
Have label elements that tick the radio button for that box (via id/for) instead of links.
<label tab-index="0" for="chk-box--red">Show red box</label>
In the above, note that I've added tab-index to the label so it show sup in the tabbing order. We probably also want CSS that underlines it or similar.
Have a CSS rule that says the .box immediately after a checked radio button should be display: block:
input[name=box-controller]:checked + .box {
display: block;
}
Live example:
.box {
height: 100px;
width: 100px;
}
/* Hide boxes inside the outer box until/unless shown */
.box .box {
display: none;
}
label {
text-decoration: underline;
}
input[name=box-controller] {
display: none;
}
input[name=box-controller]:checked + .box {
display: block;
}
.box--red {
background-color: #ff0000;
}
.box--green {
background-color: #00ff00;
}
.box--blue {
background-color: #0000ff;
}
<div>
<div class="box">
<input type="radio" name="box-controller" id="chk-box--red" checked>
<div id="boxRed" class="box box--red"></div>
<input type="radio" name="box-controller" id="chk-box--green">
<div id="boxGreen" class="box box--green"></div>
<input type="radio" name="box-controller" id="chk-box--blue">
<div id="boxBlue" class="box box--blue"></div>
</div>
<nav>
<ul>
<li><label tab-index"0" for="chk-box--red">Show red box</label></li>
<li><label tab-index"0" for="chk-box--green">Show green box</label></li>
<li><label tab-index"0" for="chk-box--blue">Show blue box</label></li>
</ul>
</nav>
</div>
Important caveat: With the above, the URL is no longer driving the process (it doesn't change as you choose boxes). That's because you can't have a label inside an a, and if you put the a inside the label because it prevents the label doing its job. If having the state in the URL is important to you, look at the JavaScript solution (which doesn't repeat itself) below.
You indicated that your concern with the JavaScript solution was that you were repeating a lot of code. There's no need to do that. Just for what it's worth, here's a JavaScript solution driven the hash fragment that works regardless of how many boxes you have; comments within:
// The function that shows the current box, hiding others
function showCurrentBox() {
// Get the box to show, defaulting to `boxRed`
const hash = location.hash.replace(/^#/, "") || "boxRed";
// Hide any box we've previously shown
// (Note the use of optional chaining, since `querySelector` may return `null`)
document.querySelector(".box.showing")?.classList.remove("showing");
// Show the box (again with optional chaining in case the fragment doesn't identify a box)
document.getElementById(hash)?.classList.add("showing");
}
// Run on startup
showCurrentBox();
// Run whenver the hash changes
window.addEventListener("hashchange", showCurrentBox);
.box {
height: 100px;
width: 100px;
}
/* Hide boxes inside the outer box until/unless shown */
.box .box {
display: none;
}
.box.showing {
display: block;
}
.box--red {
background-color: #ff0000;
}
.box--green {
background-color: #00ff00;
}
.box--blue {
background-color: #0000ff;
}
<div>
<div class="box">
<div id="boxRed" class="box box--red showing"></div>
<div id="boxGreen" class="box box--green"></div>
<div id="boxBlue" class="box box--blue"></div>
</div>
<nav>
<ul>
<li>Show red box</li>
<li>Show green box</li>
<li>Show blue box</li>
</ul>
</nav>
</div>
Adding boxes to that is just a matter of defining their CSS and giving them an ID; the JavaScript code doesn't change.
With this solution, the URL does drive the boxes. Bookmark the URL showing the green box, and that's what shows when you come back to it.

You can keep things DRY with JavaScript by caching all the boxes first, and using data attributes instead of ids. Initialise all the boxes as display: none.
Add one event listener to the ul element (using event delegation to watch for events from its child elements as they "bubble up" the DOM), switch off all the boxes by looping over the boxes and removing a show class, and then adding a show class (display: block;) to the element that corresponds to the data-id of the button that was clicked.
You can add as many boxes/buttons as you want as you can see in this example.
// Cache the boxes, and the list element, and attach
// one listener to the list element
const boxes = document.querySelectorAll('.box');
const list = document.querySelector('ul');
list.addEventListener('click', handleClick);
function handleClick(e) {
// If the child element that fired the event
// is a button
if (e.target.matches('button')) {
// Destructure the id from its dataset
const { id } = e.target.dataset;
// Iterate over all the boxes removing the show class
boxes.forEach(box => box.classList.remove('show'));
// Grab the box which has a class that corresponds
// to the id: `.red` for example
const current = document.querySelector(`.${id}`);
// And then show that box
current.classList.add('show');
}
}
.box { display: none; padding: 0.3em; color: white; }
.show { display: block; }
.red { background-color: red; }
.green { background-color: green; }
.blue { background-color: blue; }
.orange { background-color: orange; }
.black { background-color: black; }
ul { margin-left: 0; padding: 0; }
li { display: inline; }
button:hover { cursor: pointer; background-color: #fffff0; }
<div>
<nav>
<ul>
<li><button data-id="red">Red</button></li>
<li><button data-id="green">Green</button></li>
<li><button data-id="blue">Blue</button></li>
<li><button data-id="orange">Orange</button></li>
<li><button data-id="black">Black</button></li>
</ul>
</nav>
<div class="boxes">
<div class="box red">Red</div>
<div class="box green">Green</div>
<div class="box blue">Blue</div>
<div class="box orange">Orange</div>
<div class="box black">Black</div>
</div>
</div>
Additional documentation
dataset
Destructuring assignment
matches

Related

jQuery children elements are not cooperate

How it should work:
Open (toggle .show class) on div.user, and displays the .userSub div.
If I click on another div.user, close (remove .show class) and opens the clicked div.userSub
If I click on the already .show-ed div.user (NOT .userSub), it'd close the target div.user.
Almost works but the problem:
when .userSub div is .show-ed, I can only click to close on the .userSub div, not the .user div. However that would be goal. :)
I've tried to eliminate the problem. Probably the .user selection is wrong and I should use stopPropagation() somewhere, or I should be more specific with the child elements, but I can't figure it out.
let $active
$(document).ready(() => {
$(".user").click(function(e) {
if ($active != null) {
$active.toggleClass("show")
}
$(e.target).children().toggleClass("show")
$active = $(e.target).children()
})
})
.user {
background-color: gray;
padding: 20px;
margin: 5px;
}
.userSub {
display: none;
padding: 20px;
background-color: lightgray;
color: black;
margin: 5px;
}
.show {
display: block;
}
button {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="user">
name 1
<div class="userSub">details 1<button>more 1</button></div>
</div>
<div class="user">
name 2
<div class="userSub">details 2<button>more 2</button></div>
</div>
<div class="user">
name 3
<div class="userSub">details 3<button>more 3</button></div>
</div>
To achieve your goal check that the clicked element was the .user element directly, not a child of it. To do that you can use the target property of the event.
Also note that you can simplify the logic by only applying the .show class to the parent .user and having the CSS rules apply the display: block rule to the child elements based on the class on a parent. Try this:
$(document).ready(() => {
let $users = $(".user").click(function(e) {
if (e.target !== this)
return;
$users.not(this).removeClass('show');
$(this).toggleClass("show")
})
})
.user {
background-color: gray;
padding: 20px;
margin: 5px;
}
.userSub {
display: none;
padding: 20px;
background-color: lightgray;
color: black;
margin: 5px;
}
.user.show .userSub {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="user">
name 1
<div class="userSub">details 1<button>more 1</button></div>
</div>
<div class="user">
name 2
<div class="userSub">details 2<button>more 2</button></div>
</div>
<div class="user">
name 3
<div class="userSub">details 3<button>more 3</button></div>
</div>

Not sure how to do this menu [duplicate]

I'm working on a site that needs to (a) work without JavaScript and (b) be keyboard-accessible.
I have used the label target trick to build a tab view (https://css-tricks.com/functional-css-tabs-revisited/), but I've noticed that it relies on the label being clicked. I can't figure out how to make it work with the keyboard. Is this possible?
.tabs {
background-color: #eee;
min-height: 400px;
}
.tabs__list {
border-bottom: 1px solid black;
display: flex;
flex-direction: row;
list-style: none;
margin: 0;
padding: 0;
position: relative;
}
.tabs__tab {
padding: 0.5rem;
}
.tabs__content {
display: none;
left: 0;
padding: 0.5rem;
position: absolute;
top: 100%;
}
.tabs__input {
display: none;
}
.tabs__input+label {
cursor: pointer;
}
.tabs__input:focus,
.tabs__input:hover {
color: red;
}
.tabs__input:checked+label {
color: red;
}
.tabs__input:checked~.tabs__content {
display: block;
}
<div class="tabs">
<ul class="tabs__list">
<li class="tabs__tab">
<input class="tabs__input" type="radio" id="tab-0" name="tab-group" checked>
<label for="tab-0" class="tabs__label" tabindex="0" role="button">Tab 0</label>
<div class="tabs__content">
Tab 0 content
</div>
</li>
<li class="tabs__tab">
<input class="tabs__input" type="radio" id="tab-1" name="tab-group">
<label for="tab-1" class="tabs__label" tabindex="0" role="button">Tab 1</label>
<div class="tabs__content">
Tab 1 content
</div>
</li>
</ul>
</div>
Accepted answer is not an accessible solution.
I have made some corrections and some observations here. Do not use the accepted answer in production if you stumble across this question in the future. It is an awful experience with a keyboard.
The answer below fixes some of the CSS issues to make it more accessible.
However I would recommend you reconsider the no JavaScript requirement.
I can understand having a good fall-back (which the example I give below with the fixes is) but there is no way you can make a fully accessible set of CSS only tabs.
Firstly you should use WAI-ARIA to complement your HTML to make things even more clear for screen readers. See the tabs examples on W3C to see what WAI-ARIA roles you should be using. This is NOT possible without JavaScript as states need to change (aria-hidden for example should change).
Secondly, you should be able to use certain shortcut keys. Press the home key for example in order to return to the first tab, something you can only do with a little JS help.
With that being said here are a few things I fixed with the accepted answer to at least give you a good starting point as your 'no JavaScript fallback'.
Problem 1 - tabindex on the label.
By adding this you are creating a focusable element that cannot be activated via keyboard (you cannot press space or Enter on the label to change selection, unless you use JavaScript).
In order to fix this I simply removed the tabindex from the labels.
Problem 2 - no focus indicators when navigating via keyboard.
In the example the tabs only work when you are focused on the radio buttons (which are hidden). However at this point there is no focus indicator as the styling is applying styling to the checkbox when it is focused and not to its label.
In order to fix this I adjusted the CSS with the following
/*make it so when the checkbox is focused we add a focus indicator to the label.*/
.tabs__input:focus + label {
outline: 2px solid #333;
}
Problem 3 - using the same state for :hover and :focus states.
This is another bad practice that needs to go away, always have a different way of showing hover and focus states. Some screen reader and screen magnifier users will use their mouse to check they have the correct item focused and orientate themselves on a page. Without a separate hover state it is difficult to check you are hovered over a focused item.
/*use a different colour background on hover, you should not use the same styling for hover and focus states*/
.tabs__label:hover{
background-color: #ccc;
}
Example
In the example I have added a hyperlink at the top so you can see where your focus indicator is when using a keyboard.
When your focus indicator is on one of the two tabs you can press the arrow keys to change tab (which is expected behaviour) and the focus indicator will adjust accordingly to make it clear which tab was selected.
.tabs {
background-color: #eee;
min-height: 400px;
}
.tabs__list {
border-bottom: 1px solid black;
display: flex;
flex-direction: row;
list-style: none;
margin: 0;
padding: 0;
position: relative;
}
.tabs__tab {
padding: 0.5rem;
}
.tabs__content {
display: none;
left: 0;
padding: 0.5rem;
position: absolute;
top: 100%;
}
.tabs__input {
position: fixed;
top:-100px;
}
.tabs__input+label {
cursor: pointer;
}
.tabs__label:hover{
background-color: #ccc;
}
.tabs__input:focus + label {
outline: 2px solid #333;
}
.tabs__input:checked+label {
color: red;
}
.tabs__input:checked~.tabs__content {
display: block;
}
A link so you can see where your focus indicator is
<div class="tabs">
<ul class="tabs__list">
<li class="tabs__tab">
<input class="tabs__input" type="radio" id="tab-0" name="tab-group" checked>
<label for="tab-0" class="tabs__label" role="button">Tab 0</label>
<div class="tabs__content">
Tab 0 content
</div>
</li>
<li class="tabs__tab">
<input class="tabs__input" type="radio" id="tab-1" name="tab-group">
<label for="tab-1" class="tabs__label" role="button">Tab 1</label>
<div class="tabs__content">
Tab 1 content
</div>
</li>
</ul>
</div>
It is just radio buttons... Keyboard can be used to navigate through them using tab and space bar to check them.
I'd use :focus to highlight the chosen tab and the tabindex property to make it work as I wanted.
Please provide more dept if you have problem with a SPECIFIC problem related to it, and provide a basic code example here, no linking.
Since hidden inputs cannot be selected through keyboard, make them visible...
.tabs {
background-color: #eee;
min-height: 400px;
}
.tabs__list {
border-bottom: 1px solid black;
display: flex;
flex-direction: row;
list-style: none;
margin: 0;
padding: 0;
position: relative;
}
.tabs__tab {
padding: 0.5rem;
}
.tabs__content {
display: none;
left: 0;
padding: 0.5rem;
position: absolute;
top: 100%;
}
.tabs__input {
position: fixed;
top:-100px;
}
.tabs__input+label {
cursor: pointer;
}
.tabs__input:focus
.tabs__input:hover {
color: red;
}
.tabs__input:checked+label {
color: red;
}
.tabs__input:checked~.tabs__content {
display: block;
}
<div class="tabs">
<ul class="tabs__list">
<li class="tabs__tab">
<input class="tabs__input" type="radio" id="tab-0" name="tab-group" checked>
<label for="tab-0" class="tabs__label" tabindex="0" role="button">Tab 0</label>
<div class="tabs__content">
Tab 0 content
</div>
</li>
<li class="tabs__tab">
<input class="tabs__input" type="radio" id="tab-1" name="tab-group">
<label for="tab-1" class="tabs__label" tabindex="0" role="button">Tab 1</label>
<div class="tabs__content">
Tab 1 content
</div>
</li>
</ul>
</div>

How to set a default styling to element if :target doesn't exist

I have a header with 3 links, all linking to a specific div with a corresponding id:
body {
font-size: 32px;
}
.links {
display: flex;
a {
padding: 10px;
}
}
.box:not(:target) {
display: none;
}
#box1 {
background-color: crimson;
}
#box2 {
background-color: darkgreen;
}
#box3 {
background-color: gold;
}
<div class="links">
Box1
Box2
Box3
</div>
<div class="box" id="box1">Box1 content</div>
<div class="box" id="box2">Box2 content</div>
<div class="box" id="box3">Box3 content</div>
I want to use the CSS pseudo class to turn the selected element from display:none to display:block when targetted. I achieved this using .box:not(:target) { display:none }.
The problem is that I would like to default the boxes to show the first box (#box1) if :target does not exist amongst the three boxes with css only if possible, any help would be greatly appreciated!
Follow below the snippet, hope your problem will fix with html and css,
body {
font-size: 32px;
}
.links {
display: flex;
a {
padding: 10px;
}
}
.box:not(:target) {
display: none;
}
#box1{
display: block;
}
#box2:target ~ #box1,
#box3:target ~ #box1{
display: none;
}
#box1 {
background-color: crimson;
}
#box2 {
background-color: darkgreen;
}
#box3 {
background-color: gold;
}
<div class="links">
Box1
Box2
Box3
</div>
<div class="box" id="box2">Box2 content</div>
<div class="box" id="box3">Box3 content</div>
<div class="box" id="box1">Box1 content</div>
the box1 is default and when you trigger the box2, box3 you can see box1 will get display none.
mainly it's working for "general sibling selector (~)"
Create new css class called BoxControl consider this in all <a> elements for trigger show/hide event.
Then Add .active css class and add it to default class list of the element you want to show in first view as shown bellow.
Finally, implement JS as for your HTML structure tell that is your best option otherwise you'll have to modify your HTML.
SCSS/JS
Codepen Link
CSS/JS
// Capture all elements of <a> output should be in an array
var box = document.getElementsByClassName("boxControl");
// Create new variable i stands for index to be used in for loop
var i;
// Loop through all elements been found in box variable
for (i = 0; i < box.length; i++) {
// Add Event Listener of Click for <a> elements found in the variable box
box[i].addEventListener("click", function(e) {
// Add e in callback function trace the element triggered this event
// In other words, which button has been clicked
var clicked =
e.target.getAttribute("href");
// Tricky bit: As per your request they should be at least
// one default active element otherwise or else will not remove any active class
if (document.querySelector(".active")) {
document.querySelector(".active").classList.remove("active");
// Use value of captured attribute (href) to target and toggle the new active class
document.querySelector(clicked).classList.toggle("active");
// Not found any active css class (box)
} else {
var clicked = e.target.getAttribute("href");
document.querySelector(clicked).classList.toggle("active");
}
})
};
body {
font-size:32px;
}
.links {
display:flex;
}
.links a {
padding:10px;
}
.active {
display:block!important;
}
#box1 {
background-color:crimson;
display: none;
}
#box2 {
background-color:darkgreen;
display: none;
}
#box3 {
background-color:gold;
display:none;
}
<div class="links">
Box1
Box2
Box3
</div>
<div class="box active" id="box1">Box1 content</div>
<div class="box" id="box2">Box2 content</div>
<div class="box" id="box3">Box3 content</div>

How to change body color when hovering over a div

I'm currently coding a very basic page for my friend and he said he wanted a box which would change color depending on which link he hovers over. I've tried a few things but none of it seem to work.
This is how the body looks:
body {
color: #fff;
background: #98adca;
text-align: center;
margin: 275px auto;
}
#box {
padding: 30px;
border: solid;
}
li {
list-style: none;
text-decoration: none;
}
a,
a:hover,
a:active,
a:visited {
color: #fff;
text-decoration: none;
}
.twt:hover {
background: #c3c0d1;
color: #fff;
}
<div id="box">
<h1>social media</h1>
<div class="twt">
<li>twitter
</li>
</div>
<div class="ig1">
<li>art instagram
</li>
</div>
<div class="ig2">
<li>regular instagram
</li>
</div>
<div class="fb">
<li>facebook
</li>
</div>
<div class="yt">
<li>youtube
</li>
</div>
</div>
But I don't get how I should write the CSS to make the box another color when just, for example, hovering over the YouTube link. In my current CSS only the background of the text is changed when hovering and not the entire box.
Try using jQuery with the "onmouseover" event:
HTML:
<div id="box">
<a onmouseover="colorChange()" onmouseout="revert()" href="#">Link</a>
</div>
Javascript:
function colorChange() {
$("#box").css("background-color", "red");
}
function revert() {
$("#box").css("background-color", "lightgrey");
}
Here is my pen: http://codepen.io/Hudson_Taylor11/pen/ozQogO
Hope this helps!
Use jQuery:
$(".twt").hover(
function() {
$("#box").css( "background-color", "#000" );
},
function() {
$("#box").css( "background-color", "#98adca" );
}
);
Let me know if you need help setting up jQuery.
From what I know. CSS doesn't be made to walk backward. All I can think about the way I can do is using jQuery to do that.
$(document).ready(function(){
$('.ig1 li a').hover(function(){
$('#box').css({'background-color': 'green'});
});
$('.ig2 li a').hover(function(){
$('#box').css({'background-color': 'blue'});
});
$('.yt li a').hover(function(){
$('#box').css({'background-color': 'red'});
});
$('.fb li a').hover(function(){
$('#box').css({'background-color': 'pink'});
});
});
body {
color: #fff;
background: #98adca;
text-align: center;
margin: 275px auto;
padding: 30px;
}
#box {
border: 3px solid #fff;
padding: 30px;
}
li {
list-style:none;
text-decoration:none;
}
a, a:hover, a:active, a:visited {
color: #fff;
text-decoration:none;
}
.twt:hover {
background: #c3c0d1;
color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="box">
<h1>social media</h1>
<div class="twt">
<li>twitter</li>
</div>
<div class="ig1">
<li>art instagram</li>
</div>
<div class="ig2">
<li>regular instagram</li>
</div>
<div class="fb">
<li>facebook</li>
</div>
<div class="yt">
<li>youtube</li>
</div>
</div>
</body>
Right, so I started thinking, you can do it with JS, but can you do it with pure CSS. Short answer - No. CSS does not allow child elements to access parent elements, because of security and other concerns. A simple Google search will show you all the things I read, there's no point of sharing docs here. But what if we trick the user, right, just hear me out. Instead of changing the colour of the parent, which is illegal, let's change the colour of a sibling - allowed by CSS LinkSo I unified your classes, for the links to share the same class (they still have separate IDs, chill). I then added a "pretend div" which will serve the purpose of the body. I stylised the "pretend", the unified div and added a "sibling on hover" CSS rule. Take a look:HTML`
<body>
<div class="box">
<h1>social media</h1>
<div class="link_divs" id="div_1">
<li>twitter</li>
</div>
<div class="link_divs" id="div_2">
<li>art instagram</li>
</div>
<div class="link_divs" id="div_3">
<li>regular instagram</li>
</div>
<div class="link_divs" id="div_4">
<li>facebook</li>
</div>
<div class="link_divs" id="div_5">
<li>youtube</li>
</div>
<div id="pretend_div">
</div>
</div>
</body>
And here's the CSS
body {
color: #fff;
background: #98adca;
text-align: center;
margin: 275px auto;
padding: 30px;
border: 3px solid #fff;
height: 100%;
}
li {
list-style:none;
text-decoration:none;
}
a, a:hover, a:active, a:visited {
color: #fff;
text-decoration:none;
}
/* IMPORTANT - This will be the new "body" */
#pretend_div{
position: absolute; /* REQUIRED */
width: 96%; /* Matching your body size */
height: 180px; /* Matching your body size */
border: 1px solid red; /* Differentiating made easy */
top:0; /* IMPORTANT - push the element to the top */
left: 0; /* IMPORTANT - push the element to the left */
margin: 275px auto; /* Grabbed the margin from your body */
padding: 30px; /* Grabbed the padding from your body */
z-index: -1; /* IMPORTANT - push the element to the back of stack */
}
/* IMPORTANT - generic link class */
.link_divs{
z-index: 0; /* IMPORTANT - set the links on-top of the pretend div */
position: relative; /* IMPORTANT - positioning */
}
/* What link you hover over ~ The pretend div */
#div_1:hover ~ #pretend_div{
background-color: #00A000; /* change bck colour */
}
#div_2:hover ~ #pretend_div{
background-color: orangered;
}
#div_3:hover ~ #pretend_div{
background-color: darkgoldenrod;
}
REMARKS I'm aware this is not the best solution, honestly - just use JS. But I wanted to try and make it happen with pure CSS. Now I tried to match the pretend div to your body as best I could, thus it looks, well, not as good as it could. I added some comments to help you understand what is happening with each line. The ones that use the "sibling style" CSS are marked by Important. Everything else is just matching your body style.JSFiddle Demo -> DEMO LINKHope that helps
instead of background try background-color

Perform action when focused

I have 3 divs. 2 of them change their color when focused. Can also an action be performed on another div when 2 of them get focused?
div {
border: 1px solid;
margin: 5px;
width: 300px;
height: 50px;
padding: 2px;
}
.myClass:focus {
background-color: yellow;
outline: none;
}
<div class="myClass" tabindex="-1">
Focus me!
</div>
<div class="myClass" tabindex="-1">
You can focus me too!
</div>
<hr />
<div class="anotherClass">
I cannot be focused, but want to change my color, when one of the other divs above me get focused.
</div>
So when 1 of the 2 upper divs get focused I want the 3rd div at the bottom to change its color.
Here you can have a look: https://jsfiddle.net/ogpvvwtg/
Sure, you can use the general sibling selector ~
.myClass:focus ~ .anotherClass {
background-color: red;
outline: none;
}
div {
border: 1px solid;
margin: 5px;
width: 300px;
height: 50px;
padding: 2px;
}
.myClass:focus {
background-color: yellow;
outline: none;
}
.myClass:focus ~ .anotherClass {
background-color: red;
outline: none;
}
<div class="myClass" tabindex="-1">
Focus me!
</div>
<div class="myClass" tabindex="-1">
You can focus me too!
</div>
<hr />
<div class="anotherClass">
I cannot be focused, but want to change my color, when one of the other divs above me get focused.
</div>
you can do this with a little bit of javascript which might give you more control of the things you want to color.
colorDiv3 = function() {
window.document.getElementById("div3").style.backgroundColor = "lightGreen";
}
div {
border: 1px solid;
margin: 5px;
width: 300px;
height: 50px;
padding: 2px;
}
.myClass:focus {
background-color: yellow;
outline: none;
}
<div class="myClass" tabindex="-1" onFocus="colorDiv3()">
Focus me!
</div>
<div class="myClass" tabindex="-1" onFocus="colorDiv3()">
You can focus me too!
</div>
<hr />
<div id="div3" class="anotherClass">
I cannot be focused, but want to change my color, when one of the other divs above me get focused.
</div>
You can also accomplish this using JavaScript:
First give the divs IDs:
<div id="topDiv" class="myClass" tabindex="-1">
etc...
Then you can find them with:
var top_div = document.getElementById('top_div');
var middle_div = document.getElementById('middle_div');
var bottom_div = document.getElementById('bottom_div');
Assign an event listener to the objects. This allows you to call a function when an element is focused:
top_div.addEventListener("focus", changeBottomDivColor);
middle_div.addEventListener("focus", changeBottomDivColor);
And finally, the function to actually change the color:
function changeBottomDivColor() {
bottom_div.style.backgroundColor = "red";
}