CSS n'th class in another class - html

I just started to FE after a couple of years in BE.
Developing an analytics card with using Angular on FE and .net Core on BE.
Stucked on a point to find out the best practice about to change background-color: property of a class beneath of main class.
<div class="row">
<div class="journey-card-bottom">
<div *ngFor="let bottom of top.breakDown | keyvalue: originalOrder">
<div>
<span>{{bottom.key}}</span>
</div>
<div class="row">
<div class="col-lg-10">
<div class="progress">
<div class="progress-bar" role="progressbar"
[ngStyle]="{'width': bottom.value > 0 ? bottom.value + '%' : '8px'}"></div>
<span class="percentage-value">{{bottom.value}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
Screenshot to the desired outcome
In my CSS;
.journey-card-bottom {
border: 1px solid #DADCDD;
box-sizing: border-box;
padding: 10px;
line-height: 3;
width: 100%;
height: 435px;
}
.progress {
background-color: white !important;
margin-top: 5px;
}
.progress-bar {
border-radius: 0.25rem;
height: 8px;
align-self: center;
background-color: #0B4886;
}
.journey-card-bottom .progress-bar:nth-of-type(1) {
background-color: #68D391;
}
.journey-card-bottom .progress-bar:nth-of-type(2) {
background-color: #FCAF65;
}
It seems :nth-of-type(1) changes the background color but not only for 1st bar, for all of them.
:nth-of-type(2)does not effect at all i guess because there is no direct parent-child relation between each other.
On the other hand i know i can achieve with using [ngStyle] based on the item index in [ngFor] however i'm not sure if it's the best practice or not.

:nth-of-type() applies to sibling elements. Since .progress-bar is the first sibling within .progress and has no other siblings with the class .progress-bar, only the styles declared in .journey-card-bottom .progress-bar:nth-of-type(1) will be applied. Here is a code snippet showing your CSS working by changing the HTML structure:
.journey-card-bottom {
border: 1px solid #DADCDD;
box-sizing: border-box;
padding: 10px;
line-height: 3;
width: 100%;
height: 435px;
}
.progress {
background-color: white !important;
margin-top: 5px;
}
.progress-bar {
border-radius: 0.25rem;
height: 8px;
align-self: center;
background-color: #0B4886;
}
.journey-card-bottom .progress-bar:nth-of-type(1) {
background-color: #68D391;
}
.journey-card-bottom .progress-bar:nth-of-type(2) {
background-color: #FCAF65;
}
<div class="journey-card-bottom">
<div class="progress">
<div class="progress-bar" role="progressbar"></div>
<span class="percentage-value">90</span>
<div class="progress-bar" role="progressbar"></div>
<span class="percentage-value">60</span>
</div>
</div>
To solve your issue, I would suggest using :nth-of-type() on the top-level element of the for loop. In the below example, the top-level element has the class .target-class:
.journey-card-bottom {
border: 1px solid #DADCDD;
box-sizing: border-box;
padding: 10px;
line-height: 3;
width: 100%;
height: 435px;
}
.progress {
background-color: white !important;
margin-top: 5px;
}
.progress-bar {
border-radius: 0.25rem;
height: 8px;
align-self: center;
background-color: #0B4886;
}
.target-class:nth-of-type(1) .progress-bar {
background-color: #68D391;
}
.target-class:nth-of-type(2) .progress-bar {
background-color: #FCAF65;
}
<!-- Rendered HTML from the component -->
<div class="row">
<div class="journey-card-bottom">
<div class="target-class">
<div>
<span>Passed</span>
</div>
<div class="row">
<div class="col-lg-10">
<div class="progress">
<div class="progress-bar" role="progressbar"></div>
<span class="percentage-value">90</span>
</div>
</div>
</div>
</div>
<div class="target-class">
<div>
<span>Referred</span>
</div>
<div class="row">
<div class="col-lg-10">
<div class="progress">
<div class="progress-bar" role="progressbar"></div>
<span class="percentage-value">60</span>
</div>
</div>
</div>
</div>
</div>
</div>

Related

How to apply CSS style only if the last child is visible

I have this issue where I need to apply some style to a div only if it's next to a visible item (even if there's non visible items in between, but not if all the items following the current one are all invisible), as shown here:
https://stackblitz.com/edit/js-3nulnw?file=style.css
.container {
display: flex;
flex-grow: 1;
padding: 5px;
}
.content {
border: 1px solid #000000;
border-radius: 4px;
width: 50%;
padding: 10px;
}
.addon {
width: 10%;
background-color: #ff0000;
border: 1px solid #000000;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-left: none;
}
.addon.hidden {
display: none;
}
.content:not(:last-child),
.addon:not(:last-child) {
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
<div class="container">
<div class="content">This is shown correctly (no addons)</div>
</div>
<div class="container">
<div class="content">This is shown correctly (one addon)</div>
<div class="addon"></div>
</div>
<div class="container">
<div class="content">
This is shown correctly (multiple addons, one is hidden)
</div>
<div class="addon hidden"></div>
<div class="addon"></div>
</div>
<div class="container">
<div class="content">This is shown correctly (multiple addons)</div>
<div class="addon"></div>
<div class="addon"></div>
</div>
<div class="container">
<div class="content">This should have all rounded borders</div>
<div class="addon hidden"></div>
</div>
<div class="container">
<div class="content">This should have all rounded borders</div>
<div class="addon"></div>
<div class="addon hidden"></div>
</div>
I have tried looking on the internet but to no avail, but I'm probably looking for the wrong answer (most of what I found were other SO questions saying there's no CSS selector for non visible item), so alternative ways to do this are welcome (possibly without JS)
Yes it is possible. I try to understand your question and get this result. Please expalin more your question
https://developer.mozilla.org/en-US/docs/Web/CSS/:is
We can get it through (:is) pseudo-class function. we can check if div has class like visible in below example case then we can apply style to its next div throught (+) adjacent sibling selector or (~) general sibling selector. I hope example will clear what I want to say
<div class="container">
<div class="content">This is shown correctly (no addons)</div>
</div>
<div class="container">
<div class="content">This is shown correctly (one addon)</div>
<div class="addon"></div>
</div>
<div class="container">
<div class="content">
This is shown correctly (multiple addons, one is hidden)
</div>
<div class="addon hidden"></div>
<div class="addon"></div>
</div>
<!-- [ADD 'visible' CLASS BEFORE OF TARGET CONTAINER] -->
<div class="container visible">
<div class="content">This is shown correctly (multiple addons)</div>
<div class="addon"></div>
<div class="addon"></div>
</div>
<div class="container">
<div class="content">This should have all rounded borders</div>
<div class="addon hidden"></div>
</div>
<div class="container">
<div class="content">This should have all rounded borders</div>
<div class="addon"></div>
<div class="addon hidden"></div>
</div>
and its css will be
.container {
display: flex;
flex-grow: 1;
padding: 5px;
}
.content {
border: 1px solid #000000;
border-radius: 4px;
width: 50%;
padding: 10px;
}
.addon {
width: 10%;
background-color: #ff0000;
border: 1px solid #000000;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-left: none;
}
.addon.hidden {
display: none;
}
.content:not(:last-child),
.addon:not(:last-child) {
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.container:is(.visible) + .container{
background-color: rebeccapurple;
color: white;
/* Your style here */
}
.container:is(.visible) + .container .addon{
background-color: brown;
color: white;
/* Your style here */
}
I found a horrible but apparently effective way of achieving what I wanted
https://stackblitz.com/edit/js-4hkorq?file=style.css
.container {
display: flex;
flex-grow: 1;
padding: 5px;
}
.content {
border: 1px solid #000000;
border-radius: 4px;
width: 50%;
padding: 10px;
}
.addon {
width: 10%;
background-color: #ff0000;
border: 1px solid #000000;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
border-left: none;
}
.addon.hidden {
/* display: none; */
visibility: hidden;
width: 0px;
}
.content:not(:last-child),
.addon:not(:last-child) {
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.container > div:last-of-type.hidden::before {
content: '';
border: 1px solid #000000;
border-radius: 4px;
border-left: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
height: 100%;
display: flex;
width: 4px;
visibility: visible;
position: relative;
top: -1px;
}
.container > .addon + div:last-of-type.hidden::before {
background-color: #ff0000;
}
<div class="container">
<div class="content">This is shown correctly (no addons)</div>
</div>
<div class="container">
<div class="content">This is shown correctly (one addon)</div>
<div class="addon"></div>
</div>
<div class="container">
<div class="content">
This is shown correctly (multiple addons, one is hidden)
</div>
<div class="addon hidden"></div>
<div class="addon"></div>
</div>
<div class="container">
<div class="content">This is shown correctly (multiple addons)</div>
<div class="addon"></div>
<div class="addon"></div>
</div>
<div class="container">
<div class="content">This should have all rounded borders</div>
<div class="addon hidden"></div>
</div>
<div class="container">
<div class="content">This should have all rounded borders</div>
<div class="addon"></div>
<div class="addon hidden"></div>
</div>
The trick is to use visibility: hidden and width: 0 instead of display: none, then add a ::before pseudo element that adds the border. It has the drawback of adding 4 pixels to the element (in order to have a 4 pixels border radius it needs to be at least 4 pixels wide) but it is acceptable in my case and (albeit with some tweaks) it also worked in my application.
For some reason I had to add top: -1px because it wouldn't align otherwise, but in my application I didn't need to do
These are the major changes to CSS
.container {display: table; table-layout: fixed; width: 100%...}
.addon {display: table-cell; position: relative; right: 5px;
z-index: 1; padding-right: 5px;...}
.addon+.addon {right: 10px; padding-right: 10px;...}
.content {display: table-cell;}
Since this is a pure CSS solution, the tags were changed so that :*-type-of works effectively. If you want a uniform height, add a div inside .content and give it an absolute height (ie px)
section:first-of-type > div {
border-top: 1px solid #000000;
}
section:last-of-type > div {
border-bottom: 1px solid #000000;
}
.container {
display: table;
table-layout: fixed;
width: 100%;
}
.content {
display: table-cell;
padding: 15px;
width: 50%;
border-left: 1px solid #000000;
border-right: 1px solid #000000;
border-top: 0.5px solid #000000;
border-bottom: 0.5px solid #000000;
border-radius: 4px;
}
.addon {
display: table-cell;
width: 10%;
position: relative;
right: 5px;
padding-right: 5px;
z-index: 1;
background-color: #ff0000;
border-left: 0;
border-right: 1px solid #000000;
border-top: 0.5px solid #000000;
border-bottom: 0.5px solid #000000;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.addon.hidden {
display: none;
}
.addon+.addon {
right: 10px;
padding-right: 10px;
}
<section class="container">
<div class="content">This is shown correctly (no addons)</div>
</section>
<section class="container">
<div class="content">This is shown correctly (one addon)</div>
<aside class="addon visible"></aside>
</section>
<section class="container">
<div class="content">
This is shown correctly (multiple addons, one is hidden)
</div>
<aside class="addon hidden"></aside>
<aside class="addon visible"></aside>
</section>
<section class="container">
<div class="content">This is shown correctly (multiple addons)</div>
<aside class="addon visible"></aside>
<aside class="addon visible"></aside>
</section>
<section class="container">
<div class="content">This should have all rounded borders</div>
<aside class="addon hidden"></aside>
</section>
<section class="container">
<div class="content">This should have all rounded borders</div>
<aside class="addon visible"></aside>
<aside class="addon hidden"></aside>
</section>

Positioning elements with CSS

I know it is dumb question, but i am struggling with following problem
It is one of my menu buttons. I want div the represents icon (marked red with circle) be on the left side of the button and the text on the right (name (blue) above description (purple)). By the way, i am going to have plenty of those buttons and i want them appear in column (block).
My current problem is that icon div (red) and text div (green dashed) wont place inline.
My HTML is:
<style>
.HomeMenuNavbarButton {
text-decoration: none;
color : black;
border-style:outset;
border-width:4px;
border-radius:15px;
display:block;
padding:4px;
}
.circle {
width: 50px;
height: 50px;
-webkit-border-radius: 25px;
-moz-border-radius: 25px;
border-radius: 25px;
border-color: black;
border-style: dashed;
display: inline-block;
vertical-align: top;
}
</style>
<div class="container">
<div class="row">
#foreach (var node in Model.Nodes)
{
if (!(node.IsRootNode) && node.Children.Any())
{
<div class="col-md-4">
<button type="button" style="display:inline;" class="btn btn-info" data-toggle="collapse" data-target="#("#relatedNavList" + node.Title) ">#node.Title</button>
<div id="#("relatedNavList" + node.Title)" class="collapse">
#foreach (var child in node.Children)
{
<div class="HomeMenuNavbarButton" style="display:block;">
<div style="background-color:red;display:inline">
<div class="circle">
</div>
</div>
<div style="border-color: green; border-style: dashed; display:inline-block">
<div style="background-color:blue">#(child.Title)</div>
<div style="background-color:purple">#(child.Description)</div>
</div>
</div>
}
</div>
</div>
}
}
</div>
</div>
When you want to display stuff side by side in CSS, the easiest way is to use flexbox. Try to add display : flex; to your HomeMenuNavBar class.
Here is a complete document about flexbox from the Mozilla team.
Using a wrapper defined as a flexbox
.wrapper {
display: flex;
align-items: center;
justify-content: space-between;
width: 150px;
}
.circle {
height: 25px;
width: 25px;
border: medium dashed darkgray;
border-radius: 50%;
}
button {
background: dodgerblue;
color: white;
border-radius: 3px;
border: thin solid lightblue;
padding: 0.5em;
}
<div class="wrapper">
<button>Button</button>
<div class="circle"></div>
<span>Text</span>
</div>
You can do that just with display:inline-block on your button's elements
.elementButton
{
display:inline-block;
}
.circle {
width: 50px;
height: 50px;
-webkit-border-radius: 25px;
-moz-border-radius: 25px;
border-radius: 25px;
border-color: black;
border-style: dashed;
display: inline-block;
vertical-align: top;
}
.HomeMenuNavbarButton
{
display:block;
margin:5px;
}
<div class="HomeMenuNavbarButton">
<div class="circle elementButton">
</div>
<div class="elementButton">
<div>Title one</div>
<div>Content</div>
</div>
</div>
<div class="HomeMenuNavbarButton">
<div class="circle elementButton">
</div>
<div class="elementButton">
<div >Title two</div>
<div>Content</div>
</div>
</div>

Bootstrap change $grid-gutter-width

I am using Bootstraps grid system and I need about a 2px space between each column. I've tried Column-Gap but nothing.
Could anyone help?
Code HTML:
<div class="container">
<div class="row">
<div class="col-md-3" id="one">
<h3>Pink</h3>
</div>
<div class="col-md-3" id="two">
<h3>Purple</h3>
</div>
<div class="col-md-3" id="three">
<h3>Green</h3>
</div>
<div class="col-md-3" id="four">
<h3>Orange</h3>
</div>
</div>
<div class="row2">
<div class="col-md-3" >
<h3>Things that are Pink</h3>
<p>Pigs</p>
<p>Barbie</p>
<p>Some Skins</p>
<p>Ham</p>
</div>
<div class="col-md-3" >
<h3>Things that are Purple</h3>
<p>Prince</p>
<p>Goths</p>
<p>Paint</p>
<p>Berries</p>
</div>
<div class="col-md-3" >
<h3>Things that are Green</h3>
<p>Grass</p>
<p>Peas</p>
<p>Leafs</p>
<p>Apple</p>
</div>
<div class="col-md-3" >
<h3>Things that are Orange</h3>
<p>Orange</p>
<p>Ice-Lolly</p>
<p>Essex</p>
<p>Carrots</p>
</div>
</div>
</div>
</body>
</html>
Code: CSS
body {
font-family: 'Roboto Mono', monospace;
}
#media screen and (min-width: 768px)
.jumbotron {
padding-top: 48px;
padding-bottom: 48px;
}
.jumbotron {
text-align: center;
}
.container {
text-align: center;
}
#one {
border: 5px solid pink;
border-radius: 20px;
background-color: pink;
color: white;
}
#two {
border: 5px solid purple;
border-radius: 20px;
background-color: purple;
color: white;
}
#three {
border: 5px solid green;
border-radius: 20px;
background-color: green;
color: white;
}
#four {
border: 5px solid orange;
border-radius: 20px;
background-color: orange;
color: white;
}
.row2 {
margin-top: 30px;
margin-right: -15px;
margin-left: -15px;
}
A quick guide to resizing Bootstrap’s gutter width
Resizing Bootstrap's Gutter
A simple method of changing Bootstrap's default gutter size.
HTML
<div class="gutter-2 row">
<div class="col-md-6"></div>
<div class="col-md-6"></div>
`
CSS
.gutter-2.row {
margin-right: -1px;
margin-left: -1px;
}
.gutter-2 > [class^="col-"], .gutter-2 > [class^=" col-"] {
padding-right: 1px;
padding-left: 1px;
}`
to change the gutter you have two way:
change #grid-gutter-width in variables.less:327, but then you will need to compile the generated css yourself.
change #grid-gutter-width and download a new custom build at Bootstrap#Customize
Note that the customize section will be dropped in twitter bootstrap 4.

Alternative to display flex for event tracker

I currently have an event tracker made using html and css. My issue is that I would like to get ride of display: flex; due to browser-compatibility issues. Is there an alternative to achieve the same result? I tried using display:inline-block because without flex all steps were coming in different lines.
HTML:
<div class="container">
<div class="row event">
<div class="col-xs-3 event-step">
<p class="event-stepnum">Step 1</p>
<div class="progress">
<div class="progress-bar"></div>
</div>
</div>
<div class="col-xs-3 event-step complete">
<p class="event-stepnum">Step 2</p>
<div class="progress">
<div class="progress-bar"></div>
</div>
</div>
<div class="col-xs-3 event-step">
<p class="event-stepnum">Step 3</p>
<div class="progress">
<div class="progress-bar"></div>
</div>
</div>
</div>
</div>
CSS:
.event > .event-step {
padding: 0;
position: relative;
}
.event > .event-step .event-stepnum {
color: #595959;
font-size: 16px;
margin-bottom: 5px;
}
.steps .step-on,
.steps .step-done {
background-color: #1b7e28;
color: #1b7e28;
border: 1px solid transparent;
}
.progress {
position: relative;
border-radius: 0px;
height: 5px;
box-shadow: none;
margin: 20px 0;
}
.progress > .progress-bar {
width: 0px;
box-shadow: none;
background: #fbe8aa;
}
.event-step.complete > .progress > .progress-bar {
width: 100%;
}
.row {
display:flex;
}
JSFiddle Demo
Just replace the display:flex by display:inline-block and give your step divs a fixed width:
.event > .event-step {
padding: 0;
position: relative;
width: 200px;
}
.row {
display: inline-block;
}
https://jsfiddle.net/onk2cqhg/

Setting the variable percentage width of HTML elements next to other variable-width elements

I have a HTML structure with given CSS.
Both caption and progress elements should be rendered in same line. caption elements should not have fixed width and progress elements should fill up the rest of the space next to caption based on their inline-set width, which means that every progress element will have a different total pixel-width but should fill up only the given percentage of available space.
HTML structure and CSS rules can be changed in any way.
Is it possible to solve this problem with CSS only?
.table {
padding: 15px;
width: 280px;
border: 1px solid black;
font-family: sans-serif;
font-size: 12px;
}
.caption {
float: left;
}
.progress {
height: 14px;
border: 1px solid white;
border-radius: 4px;
background-color: green;
overflow: hidden;
}
.value {
margin-left: 5px;
}
<div class="table">
<div class="row">
<div class="caption">Short text: </div>
<div class="progress" style="width:11.65%">
<span class="value">11.65</span>
</div>
</div>
<div class="row">
<div class="caption">A bit longer text: </div>
<div class="progress" style="width:100%">
<span class="value">100.00</span>
</div>
</div>
<div class="row">
<div class="caption">X: </div>
<div class="progress" style="width:45.50%">
<span class="value">45.50</span>
</div>
</div>
</div>
Have you considered using Flexbox?
Just add this rule:
.row {
display: flex;
}
If your are concerned about browser support, an alternative would be using display:table. You should change your markup and CSS, like this:
.table {
border: 1px solid black;
font-family: sans-serif;
font-size: 12px;
padding: 15px;
width: 280px;
}
.inner-table {
display: table;
}
.row {
display: table-row;
}
.caption {
display: table-cell;
white-space: nowrap;
width: 1%;
}
.progress {
background-color: green;
border: 1px solid white;
border-radius: 4px;
display: table-cell;
height: 14px;
}
.value {
margin-left: 5px;
display:block;
width:0;
overflow: visible;
}
<div class="table">
<div class="inner-table">
<div class="row">
<div class="caption">Short text: </div>
<div style="width:1.65%" class="progress">
<span class="value">1.65</span>
</div>
<div class="remainder"></div>
</div>
</div>
<div class="inner-table">
<div class="row">
<div class="caption">A bit longer text: </div>
<div style="width:100%" class="progress">
<span class="value">100.00</span>
</div>
<div class="remainder"></div>
</div>
</div>
<div class="inner-table">
<div class="row">
<div class="caption">X: </div>
<div class="progress" style="width:45.50%">
<span class="value">45.50</span>
</div>
<div class="remainder"></div>
</div>
</div>
</div>
Please try this - padding-right: 5px; display:inline; add these properties in progress class and also remove width in progress.
Well, just for the future reference, I was playing a bit with the flexbox thingie and came up with this:
.table {
padding: 15px;
width: 280px;
border: 1px solid black;
font-family: sans-serif;
font-size: 12px;
}
.row {
display: flex;
}
.caption {
margin: 1px 5px 1px 0;
}
.progress {
flex-grow: 1;
margin: auto;
}
.progress-content {
height: 14px;
border-radius: 4px;
background-color: green;
}
.value {
margin-left: 5px;
}
<div class="table">
<div class="row">
<div class="caption">Short text:</div>
<div class="progress">
<div class="progress-content" style="width:11.65%">
<span class="value">11.65</span>
</div>
</div>
</div>
<div class="row">
<div class="caption">A bit longer text:</div>
<div class="progress">
<div class="progress-content" style="width:100%">
<span class="value">100.00</span>
</div>
</div>
</div>
<div class="row">
<div class="caption">X:</div>
<div class="progress">
<div class="progress-content" style="width:45.50%">
<span class="value">45.50</span>
</div>
</div>
</div>
</div>
If I get a solution without flexbox, will accept it as an answer :)