I have the following styling setup to apply an icon to external links, but I'm having an issue where it's applying to images that are a child of the anchor tag, which I do not want.
a:not(.btn) {
&[target="_blank"] {
&:after {
// The styles I want to apply
}
}
}
I've attempted to use the following img:not(:first-child) selector to wrap the block, but it does not seem to do what I want it to.
a:not(.btn) {
&[target="_blank"] + img:not(:first-child) {
&:after {
// The styles I want to apply
}
}
}
What is the correct way to adjust this code where it will correctly apply to any anchor tags with target="_blank" but not to those when an img tag is a child.
If you are happy to add a dash of javascript, you can achieve the effect you're after relatively straightforwardly by:
adding a class to all anchor elements with target="_blank"
removing the same class (the one you just added) from all parent nodes of image elements
Working Example:
// GET ALL THE ANCHORS WITH target="_blank"
const anchorTargetBlanks = [...document.querySelectorAll('[target="_blank"]')];
// ADD A CLASS TO ALL SUCH ANCHORS
anchorTargetBlanks.forEach(anchor => anchor.classList.add('link-contains-no-image'));
// REMOVE THAT CLASS FROM THE PARENT NODE OF EACH IMAGE
[...document.images].forEach((image) => {
if (image.parentNode.getAttribute('target') === '_blank') {
image.parentNode.classList.remove('link-contains-no-image');
}
});
ul {
padding-left: 0;
}
li {
margin: 1px;
}
img {
display: inline-block;
width: 30px;
height: 30px;
margin-right: 6px;
background-color: rgb(0, 0, 191);
vertical-align: middle;
}
.link-contains-no-image {
display: block;
padding: 6px;
color: rgb(255, 255, 255);
background-color: rgb(255, 0, 0);
}
<ul>
<li>Link 1</li>
<li><img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'/%3E" alt="Image for Link 2" />Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
<li><img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'/%3E" alt="Image for Link 5" />Link 5</li>
<li>Link 6</li>
</ul>
What you are trying to do is target a parent based on its child, and that is not possible with CSS. You need to use JS or JQuery. Check these answers for more detailed suggestions.
Set parent style via child or
Is there a CSS parent selector?
Related
I have a menu with a dropdown that I've centered in the page. As I've positioned it absoutely, when the dropdown is opened, the menu moves upwards (to account for the increased height due to the menu being open).
I cannot quite work out what a better way around this is? The ideal behaviour is that before the dropdown is open, the menu is perfectly centered, and then when a dropdown is opened, the top of the menu stays in place.
I'm looking to see if there is a CSS only method of maintaining the positioning. Otherwise, I'll implement some JS to position the menu on load.
var dropdown = document.getElementById("dropdown");
var show = false;
function showDropdown() {
var dropdownList = document.getElementById("dropdownList");
if (show) {
dropdownList.classList.remove("show");
show = false;
} else {
dropdownList.classList.add("show");
show = true;
}
}
dropdown.addEventListener("click", showDropdown);
.parent {
height: 100vh;
width: 100vw;
background-color: #aaa;
}
.list {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.dropdown > ul {
display: none;
}
.dropdown > ul.show {
display: block;
}
<div class="parent">
<ul class="list">
<li class="dropdown">Item One
<ul id="dropdownList">
<li>Dropdown 1</li>
<li>Dropdown 2</li>
</ul>
</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
</div>
Well the problem is you have your content aligned vertically using translate and top. I've changed this to be margin-top, but its not going to be perfect.
The automatic vertical centering of your previous method will sadly result in your content being pushed upward when it gets talked; as that is how vertical alignment works.
You basically have to manually determine where on the page it should be aligned with.
var dropdown = document.getElementById("dropdown");
var show = false;
function showDropdown() {
var dropdownList = document.getElementById("dropdownList");
if (show) {
dropdownList.classList.remove("show");
show = false;
} else {
dropdownList.classList.add("show");
show = true;
}
}
dropdown.addEventListener("click", showDropdown);
.parent {
height: 100vh;
width: 100vw;
background-color: #aaa;
}
.list {
position: absolute;
margin-top: 40vh;
}
.dropdown > ul {
display: none;
}
.dropdown > ul.show {
display: block;
}
<div class="parent">
<ul class="list">
<li class="dropdown">Item One
<ul id="dropdownList">
<li>Dropdown 1</li>
<li>Dropdown 2</li>
</ul>
</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
</div>https://stackoverflow.com/posts/66536030/edit#
I built a few websites with responsive navigation already. There are many solutions for responsive designs of website navigation if you have a static navigation.
However, for my current project I am building an user-individual dynamic navigation, so the number of navigation element as well as their contents are subject to change and are user individual. Therefore I tried different things with flexbox and floating layouts already but did not find a solution meeting my needs.
Do you have an idea how to fix the problem showed in the picture attached?
I also attached some sample code.
<!DOCTYPE html>
<html>
<head>
<style>
* {
font-family: "Avenir";
}
body {
margin: 0;
}
header {
background: #303ca2;
color: white;
margin-bottom: 20px;
display: flex;
}
h1 {
font-size: 24px;
margin: 0;
text-transform: uppercase;
font-weight: 400;
padding: 10px;
line-height: 40px;
flex-shrink: 0;
}
nav {
}
nav ul {
margin: 0;
padding: 0;
text-align: right;
}
nav ul li {
list-style: none;
display: inline-block;
font-size: 16px;
padding: 10px 10px;
line-height: 40px;
}
</style>
</head>
<body>
<header>
<h1>Title Zone</h1>
<nav>
<ul>
<li>Navigation Elem 1</li>
<li>Navigation Element 2</li>
<li>Navigation 3</li>
<li>Element 4</li>
<li>Element 5</li>
<li>Navigation 6</li>
<li>Element n</li>
</ul>
</nav>
</header>
</body>
</html>
you need use media query to set what will appear in each screen size.
In the HTML file you will define all cases including a div tag "more" with yheir li tag
but when the screen size if less than a certain number this div will recive display: none
for example:
<ul>
<li>element 1</li>
<li>element 2</li>
<li class="disabledOnMobile">element 3</li>
<li class="disabledOnMobile">element 4</li>
<div class="activeOnMobile">more...
<ul>
<li>element 3</li>
<li>element 4</li>
</ul>
</div>
</ul>
and with media query you can hide or show something based in the width screen like this:
#media only screen and (max-width: 400px) {
.disabledOnMobile {
display: none;
}
}
hiding all tag with disabledOnMobile class (element 3 and 4 showing their only with "more")
#media only screen and (min-width: 400px) {
.activeOnMobile {
display: none;
}
}
Here we hide the activeOnMobile when the screen is bigger than 400px showing only element 3 and 4 that is outside activeOnMobile class
in your case you need add the hover on "more" and set anothers settings, it's only a example, you can also add a breakpoin in any screen size. To becobe it's easier you can use some library like bootstrap.
You can lear more about media query here
I don't understand why the following code has not desired behaviour:
.toggle {
color: red;
}
:not(.list) .toggle {
font-weight:bold;
}
<div class="container">
Toggle
<ul class="list">
<li>Link 1</li>
<li>
<div class="container">
SubToggle
<ul class="list">
<li>SubLink 1</li>
<li>
SubLink 2
</li>
<li>SubLink 3</li>
</ul>
</div>
</li>
<li>Link 3</li>
</ul>
</div>
I thought that using :not() would result in applying "bold" only to main "Toggle" link but instead it applis "bold" to all of red ones. Why?
Please, note that this code is nested with same class names, I don't want to target specific levels with different css classes, I would like to target elements only with descendant selectors and other operators
Here is present also a jsFiddle to directly try.
I think you might want this:
.toggle {
color: red;
font-weight: bold;
}
div *:not(.list) .toggle {
font-weight: normal;
}
:not does not support CSS Combinators.
Your only way to do this is:
.toggle {
color: red;
}
.toggle {
font-weight:bold;
}
.list .toggle {
/* Override previous */
}
Fiddle
I tried so many times but this is the only way I can do:
.toggle {
color: red;
font-weight:bold;
}
.list .toggle{
//override
font-weight:normal;
}
This is how to use :not the right way:
add specialToggle for elements you do not want to select
SubToggle
and then css:
.toggle {
color: red;
}
.toggle:not(.specialToggle) {
font-weight:bold;
}
https://jsfiddle.net/s249tyur/3/
If the structure is always going to be the same you could try using the greater-than sign (>), it means only apply the style to the immediate children of the class.
.container > .toggle {
font-weight:bold;
}
Or if the container is not always going to have the same class, but is always a div element you could use:
div > .toggle {
font-weight:bold;
}
What I'm trying to create is a toggle that's workable without using JavaScript or jQuery. The main issue that I'm having is with getting the toggle text to switch from Open to Close when :target is applied on the #menu selector. The navigation is collapsed by default and is opened by #menu toggle.
HTML
<nav class="site-nav" id="menu">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</nav>
<section class="site-nav__toggle">
<a class="site-nav__toggle--open" href="#menu">Open</a>
<a class="site-nav__toggle--close" href="">Close</a>
</section>
CSS via SCSS
.site-nav {
border-bottom: 4px solid black;
float: left;
height: 0;
overflow: hidden;
width: 100%;
&:target {
height: 100%;
min-height: 170px;
transition: height .25s ease, min-height .25s ease;
}
}
.site-nav__toggle--open > .site-nav:target,
.site-nav__toggle--close > .site-nav {
display: none;
}
.site-nav__toggle--close > .site-nav:target,
.site-nav__toggle--open > .site-nav {
display: inline;
}
The main problem I have is that the text is not switching on the target states. Maybe a 2nd pair of eyes would help and spot the obvious if I've missed anything in this particular problem.
From W3C:
div > p
Selects all P elements where the parent is a DIV element
div + p
Selects all P elements that are placed immediately after DIV elements
I think your selectors should look like
.site-nav:target + .site-nav__toggle .site-nav__toggle--open,
.site-nav + .site-nav__toggle .site-nav__toggle--close {
display: none;
}
.site-nav:target + .site-nav__toggle .site-nav__toggle--close,
.site-nav + .site-nav__toggle .site-nav__toggle--open {
display: inline;
}
Check this codepen:
http://codepen.io/anon/pen/goAIu
Best,
Marek
Is there a way of using css pseudo-class to accomplish this: I need to add the class name of the child span (high) to the parent li?
thanks
<li class="emergency" style="background-color: #FE9D9D;">
<span class="high">250</span></li>
You cannot do this with CSS.
You can with JQuery however.
$(document).ready(function () {
$('li.emergency').each(function () {
var newClass = $(this).find('span').attr('class');
$(this).addClass(newClass);
});
});
Demo
Or you can set the background colour of the span instead. display: block; will make the span full width.
HTML
<ul>
<li class="emergency">
<span class="high">250</span>
</li>
<li class="emergency">
<span class="low">100</span>
</li>
</ul>
CSS
span {
display: block;
}
span.high {
background: red;
}
span.low {
background: green;
}
Demo