Knockout.js & Bootstrap 3 - Bread Crumb Pseudo Element - css

I have run into an interesting bug. The CSS pseudo element does not disappear when it's associated element has display: none; in Bootstrap 3.0.2's breadcrumb component. jsFiddle To test: try switching the mode in the view model from "Mode 1" to "Mode 2".
I have a breadcrumb link that I am building using knockout.js. I switch the visibility of the pure li or li with nested a with knockout's visible: onSomeCondition binding. My understanding is that the non-visible li is set with display: none;. However, this does not remove the associated li in the DOM, and I think that makes the CSS keep the pseudo element. For example, I am expecting the following:
Mode 1 / Mode 2
But I get:
/ Mode 1 / Mode 2
The relevant knockout code is:
<ol class="breadcrumb">
<li data-bind="visible: isInMode1()">
Mode 1
</li>
<li class="active" data-bind="visible: !isInMode1()">Mode 1</li>
<li data-bind="visible: isInMode2()">
Mode 2
</li>
<li class="active" data-bind="visible: !isInMode2()">Mode 2</li>
</ol>
The relevant Bootstrap 3.0.2 CSS is below. Based on the Bootstrap style sheet, the "/" character is added as a pseudo "before" element.
.breadcrumb {
padding: 8px 15px;
margin-bottom: 20px;
list-style: none;
background-color: #f5f5f5;
border-radius: 4px;
}
.breadcrumb > li {
display: inline-block;
}
.breadcrumb > li + li:before {
padding: 0 5px;
color: #cccccc;
content: "/\00a0";
}
.breadcrumb > .active {
color: #999999;
}
If there is a better way to do this, or a cross-browser solution that I am not thinking of, I would be grateful for any input. I would prefer not to hack the CSS, but that may be the cleaner solution.
Thank you
Quick Links:
Bootstrap 3.0.2 Breadcrumbs
Knockout.js visible binding documentation

Don't use the "visible" binding, the separator will show even if the element is hidden. Use the "if" and "ifnot" bindngs:
<ol class="breadcrumb">
<li data-bind="if:isInMode1()">
Mode 1
</li>
<li class="active" data-bind="ifnot:isInMode1()">Mode 1</li>
<li data-bind="if:isInMode2()">
Mode 2
</li>
<li class="active" data-bind="ifnot:isInMode2()">Mode 2</li>
</ol>

For the sake of completeness, and because I very rarely find a question I can answer that doesn't already have a brilliant answer.....this is what to do:
<ol class="breadcrumb" data-bind="foreach: contentModel.breadcrumbs">
<!-- ko if: isInMode1($data) -->
<li data-bind="css: cssClass">
</li>
<!-- /ko -->
<!-- ko ifnot: isInMode1($data) -->
<li data-bind="css: cssClass, text: displayName"></li>
<!-- /ko -->
...repeat for isInMode2.......
</ol>
The if: and ifnot: bindings only render SUB elements depending upon their evaluation.....The element that contains the if/ifnot binding is always rendered.

Related

Preventing height of a block element from pushing other block elements without absolute positioning?

https://codepen.io/arandomcodepenuser/pen/NWjYGwo
Ok, so I have this top navbar, and the problem is that I can't change the html only the styling, because I am using a Wordpress plugin, and this navbar has block elements on the navbar, and there's one of them that has a dropdown within the element and not below, and I can't use javascript to change this, I am wondering if it's possible for the dropdown embedded within the li element to push down the other elements on the navbar when it appears on hover.
Here's the html:
<div>
<ul class="top-bar__menu">
<li id="menu-item-265276" class=""><span>Find Us</span></li>
<li id="menu-item-280208" class="">
<span>About</span>
<ul class="sub-menu">
<li id="menu-item-268209" class=""><span>About Us</span></li>
<li id="menu-item-265276" class=""><span>Find Us</span></li>
<li id="menu-item-280209" class=""><span>Our Team</span></li>
</ul>
</li>
</ul>
</div>
Here's the css styling for the dropdown menu:
.sub-menu {
display: block;
}
.sub-menu li {
clear:both;
width: 100%;
}
ul.sub-menu {
display: inline;
background-color: #fff;
max-width: 100px;
}

Target the first child in a parent that doesn't have a specific class

The title is a mouthful but that's precisely what I'm trying to accomplish. I need to target the first instance where a class is not present - in this case I'm trying to hide the span in #3. This needs to be dynamic though as it won't always be #3. I tried getting sneaky with :not and :nth-of-type but its horribly wrong.
<style>
li:not(.done):nth-of-type(1).span.divider {display:none}
</style>
<-- 1 -->
<li class="wrapper done"><span class="divider"></span></li>
<-- 2 -->
<li class="wrapper done"><span class="divider"></span></li>
<-- 3 - hide this span -->
<li class="wrapper"><span class="divider"></span></li>
<-- 4 -->
<li class="wrapper"><span class="divider"></span></li>
<-- 5 -->
<li class="wrapper"><span class="divider"></span></li>
I think you will need to use two selectors for this:
/*hide all the element after .done selector without done*/
li.done ~ li:not(.done) {
display:none;
}
/*show all the element after the first one without .done*/
li.done ~ li:not(.done) ~ li {
display:list-item;
}
<ul>
<!-- 1 -->
<li class="wrapper done"><span class="divider">1</span></li>
<!-- 2 -->
<li class="wrapper done"><span class="divider">2</span></li>
<!-- 3 - hide this span -->
<li class="wrapper"><span class="divider">3</span></li>
<!-- 4 -->
<li class="wrapper"><span class="divider">4</span></li>
<!-- 5 -->
<li class="wrapper"><span class="divider">5</span></li>
</ul>
If it's always going to be after an element with the class .done then this should work: li.done + li:not(.done) .divider { display:none; }
My approach to the problem would be to use two separate rules; one to style all the elements lacking the given class-name and another to override all elements lacking the given class-name that follow an element lacking that class-name:
/* Selects all <li> elements with the 'wrapper'
class-name that does not have the 'done' class: */
li.wrapper:not(.done) {
color: limegreen;
}
/* Selects all elements, as above, that follow an
element without the 'done' class-name; effectively
we style the first occurrence using the above rule
because the first occurrence - obviously - cannot
be a general (later) sibling of a matching element: */
li.wrapper:not(.done)~li.wrapper:not(.done) {
color: red;
}
*,
::before,
::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul {
display: flex;
flex-wrap: wrap;
list-style-type: none;
width: 95vw;
margin: 0 auto;
}
li {
flex: 1 1 150px;
margin: 0.2em;
height: 10vh;
text-align: center;
line-height: 10vh;
border: 1px solid #000;
}
li.wrapper:not(.done) {
color: limegreen;
}
li.wrapper:not(.done)~li.wrapper:not(.done) {
color: red;
}
<ul>
<li class="wrapper done"><li>: 1</li>
<li class="wrapper done"><li>: 2</li>
<li class="wrapper done"><li>: 3</li>
<li class="wrapper"><li>: 4</li>
<li class="wrapper"><li>: 5</li>
<li class="wrapper"><li>: 6</li>
<li class="wrapper"><li>: 7</li>
<li class="wrapper"><li>: 8</li>
<li class="wrapper"><li>: 9</li>
<li class="wrapper"><li>: 10</li>
</ul>
References:
Negation (:not()) operator.
General sibling (~) combinator.

Is it appropriate to wrap each navigation element in a div?

I'm learning HTML + CSS and working on a website where I need to have a vertical navigation bar on the left side which will have four elements which can be interacted with. Is it standard practice to wrap each of these four elements with a div or is there a more elegant or semantic way to solve this problem? I will want each element to have unique on-click functions associated with them, which is why I thought giving them divs and classes would make the most sense for interacting with them later.
Thanks!
JSFIDDLE DEMO
HTML structure:
There are many ways to achieve a vertical navigation.
The most common would be to use ul and li:
<div id="lnav_container">
<ul id="lnav">
<li class="lnav_item">Item 1</li>
<li class="lnav_item">Item 2</li>
<li class="lnav_item">Item 3</li>
<li class="lnav_item">Item 4</li>
</ul>
</div>
Also very common to have a tags inside li.
Styling:
You can get rid of the bullets by having list-style-type: none; for the ul.
You can give them different style on hover by using :hover selector to make it more interactive.
.lnav_item {
width: 74%;
margin-top: 10px;
}
.lnav_item:first-child {margin-top: 0px;}
.lnav_item.selected {width: 86%;}
.lnav_item a {
display: inline-block;
width: 100%;
line-height: 30px;
padding: 8px 5px 5px 0px;
background-color: yellow;
color: black;
font-weight: bold;
text-decoration: none;
border-radius: 2px 12px 12px 2px;
}
.lnav_item.selected a {
background-color: green;
color: white;
font-size: 18px;
}
.lnav_item:hover a {background-color: orange;}
To get rid of a underline use text-decoration: none; and override its default coloring if you wish.
Javascript (jQuery):
It'll be easy to bind clickListener to the items:
$('.lnav_item a').on('click', function() {
//$(this) item is clicked, do whatever you want
$('.lnav_item').removeClass('selected');
$(this).parent().addClass('selected');
});
EDIT:
If you want to give each of the navigation items a different style, etc, you can achieve it different ways:
jsfiddle DEMO
You can use CSS' nth-child() selector:
.lnav_item:nth-child(2):hover a{background-color: #252F1D;}
.lnav_item:nth-child(3):hover a{background-color: white;}
If you're doing it in jQuery, alternatively you can use the function with parameter (index) and maybe use eq if needed.
$('.lnav_item > a').each(function(index) {
if(index == 0) {
//give it a different onClick, CSS rule, etc
}
//and so on
});
index is zero-based, but nth-child starts from one.
The typical HTML5 markup for a site navigation menu would be a nav element that contains an ul element:
<nav>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</nav>
If you can get your CSS/JS to work with this markup (+ class attributes or whatever you need), great.
If you need more elements, add div and/or span elements: they are meaningless, so they don’t change the semantics of your document.
NAV elements are simply LISTS.
You don't need to wrap them in anything.
Here's an example of my own Navigation Panel (I also placed it on the left-hand side of my screen)
<nav>
<ul style="list-style: none">
<h3>Main Menu</h3>
<li style="font-size: 100%"><b>Article 1</b></li>
<ul style="list-style: none">
<br>
<dt>
<li style="font-size: 100%"><a href="Article 1.1">Article
1.1</a>
</li>
<br>
<li style="font-size: 100%"><a href="Article 1.2">Article
1.2</a>
</li>
<br>
</dt>
</ul>
<br>
</nav>

Add dropdown arrow indicators to menu items that have submenus only?

I am currently trying to add arrow indicators on my navigation menu for items which have submenu options.
Currently I am using this CSS:
.mainNav li > a:after {
color: #444;
content: ' ▾';
}
But this adds a dropdown arrow to every <li> regardless of if there is a submenu or not. Is there a way with just CSS to only add this arrow to items that have sub-items?
Thanks!
No. CSS has no contains child selector. You'd probably be better to just add a class to the li element. For example:
<li class="has-child">
The Link
<ul class="child">
<li>Child 1</li>
</ul>
</li>
Your CSS selector would in turn look like:
.mainNav li.has-child > a:after {
color: #444;
content: ' ▾';
}
You could have jQuery add the class for you, if that's an option:
$('.mainNav li:has(ul)').addClass('has-child');
jsFiddle Demo
CSS has no contains child selector.
However it has various sibling selectors, only-child and not(:only-child)
Since you add indicator to the anchor, use following CSS
.mainNav li>a:not(:only-child):after {
color: #444;
content: ' ▾';
}
<div class="mainNav">
<li>
The item with child
<ul class="child">
<li>Child 1</li>
</ul>
</li>
<li>
No child item
</li>
</div>
Yes you can without any jQuery : https://css-tricks.com/targetting-menu-elements-submenus-navigation-bar/

Selector for one tag directly followed by another tag

This selects all <B> tags directly preceded by <A> tags:
A+B {
/* styling */
}
What is the selector for all <A> tags directly followed by <B> tags?
Here's sample HTML fitting my question:
<a>some text</a>
<b>some text</b>
Do you mean to style A given that it has a B element directly inside or followed? Like this:
<A>
<B>
</B>
</A>
// OR
<A>
</A>
<B>
</B>
You can't do such a thing in CSS (yet). Eric Meyer states that this kind of selector has been discussed quite a few times on the CSS mailing list, and isn’t doable. Dave Hyatt, one of the core WebKit developers, comments with a good explanation of why it can’t be done.
Check out: Shaun Inman's blog post and the comment by Eric Meyer.
David Hyatt weighs in, too.
You can’t in css.
Edit: To be a bit more helpful, if you use for example jQuery (a JavaScript library), you can use .prev().
You can ONLY do the converse: This selects all tags directly preceded by tags.
This is logically equivalent to your request.
I often use this to style a row of many checkboxes with labels
CSS:
label+input {
margin-left: 4px;
}
DOM:
<input id="a" name="a" type="checkbox"/><label for="a">...</label>
<input id="b" name="b" type="checkbox"/><label for="b">...</label>
<input id="c" name="c" type="checkbox"/><label for="c">...</label>
Although it's not very handy, nowadays you could achieve this behavior by reversing the order of your elements both when you generate the HTML and by applying the CSS rules: display: flex and flex-direction: column-reverse
ul {
display: flex;
flex-direction: column-reverse;
}
.b ~ .a {
color: red;
}
<ul>
<li class="a">A 3</li>
<li class="c">C 2</li>
<li class="c">C 1</li>
<li class="b">B 1</li>
<li class="a">A 2</li>
<li class="a">A 1</li>
</ul>
Also, if you have 2 or more inline elements, you could achieve it by applying float: right, as they will be displayed in reverse order:
ul {
float: left;
list-style-type: none;
}
li {
float: right;
}
li:not(:first-child) {
margin-right: 20px;
}
.b ~ .a {
color: red;
}
<ul>
<li class="a">A 3</li>
<li class="c">C 2</li>
<li class="c">C 1</li>
<li class="b">B 1</li>
<li class="a">A 2</li>
<li class="a">A 1</li>
</ul>
You can now use the :has() css selector (caniuse):
.first:has(+ .second) {
background: #ff0000;
}
That can be read: select all elements with class ".first" that are followed by element of class ".second"
<div class="first">Foo</div>
<div class="second">Bar</div>

Resources