CSS sibling selector not working as expected - html

I am trying to use CSS sibling selectors but seems that they are not working as per rule.
Basically, i am using panel from bootstrap and trying to change panel-heading css via rules.
I have created a similar markup to replicate the issue and Below is the JS Fiddle link for same
Link to JS Fiddle
I have also tried with below css:
.collpase + .heading{
opacity: 0.2
}
.collpase.in + .heading{
opacity: 1
}
Any ideas?

Since one can't select a previous sibling, one can use flexbox to achieve that effect by have one order in markup and another visual rendered.
Here I used flex, switched order in markup and again, visually, using flexbox property order
Now both the CSS sibling selectors ~/+ will work as they target the next sibling in the markup.
.heading {
color: #fff;
background: #000;
padding: 5px;
margin: 5px;
}
.collapse {
padding: 5px;
display: none;
order: 2 /* added property */
}
.collapse.in {
display: block;
}
.flex { /* added rule */
display: flex;
flex-direction: column;
}
.collapse ~ .heading { /* "collapse" was misspelled */
opacity: 0.2;
}
.collapse.in ~ .heading { /* "collapse" was misspelled */
opacity: 1;
}
<div class="parent">
<div class="firstChild flex">
<div class="collapse in">
Content
</div>
<div class="heading">
STep 1
</div>
</div>
<div class="secondChild flex">
<div class="collapse">
Content
</div>
<div class="heading">
STep 2
</div>
</div>
<div class="thirdChild flex">
<div class="collapse">
Content
</div>
<div class="heading">
STep 3
</div>
</div>
<div class="fourthChild flex">
<div class="collapse">
Content
</div>
<div class="heading">
STep 4
</div>
</div>
</div>
For older browsers, display: table can be used
.heading {
color: #fff;
background: #000;
padding: 5px;
margin: 5px;
}
.collapse {
padding: 5px;
display: none;
}
.collapse.in {
display: table-footer-group; /* changed property */
}
.child { /* added rule */
display: table;
}
.collapse ~ .heading { /* "collapse" was misspelled */
opacity: 0.2;
}
.collapse.in ~ .heading { /* "collapse" was misspelled */
opacity: 1;
}
<div class="parent">
<div class="first child">
<div class="collapse in">
Content
</div>
<div class="heading">
STep 1
</div>
</div>
<div class="second child">
<div class="collapse">
Content
</div>
<div class="heading">
STep 2
</div>
</div>
<div class="third child">
<div class="collapse">
Content
</div>
<div class="heading">
STep 3
</div>
</div>
<div class="fourth child">
<div class="collapse">
Content
</div>
<div class="heading">
STep 4
</div>
</div>
</div>

Related

Align active button centre in a Flex div

I have a simple HTML code which contains three button inside a flex div as bellow;
When a user click on any of the buttons, that button will have the active class.
.box {
width: 100%;
background-color: red;
text-align: center;
}
.flexbox {
width: 100%;
justify-content: center;
}
.active {
background-color: yellow;
}
<div class="box">
<h4>HELLO</h4>
<div class="flexbox">
<button class="active">ONE</button>
<button>TWO</button>
<button>THREE</button>
</div>
</div>
What I need to achieve here is the button contain the active class should always be centre aligned in side the flex box.
According to the above, the button ONE has the active class and it should be centre aligned in side the flexbox and other two buttons should go right.
You can get the idea from the image below
NOTE: Preferred to solve this with use CSS only.
If it's only 3 buttons here is an idea using CSS grid:
.box {
background-color: red;
text-align: center; /* center the grid */
}
.flexbox {
display: inline-grid;
grid-template-columns: repeat(5, 1fr); /* 5 columns */
justify-content: center; /* center the columns */
gap: 5px;
}
.active {
grid-column: 3; /* active always on the middle */
}
/* we need a "hacky" code for the second case */
.active:nth-child(2) {
grid-area:1/1;
transform:translate(calc(200% + 10px)); /* 10px = 2xgap */
}
.active:nth-child(2) ~ :last-child {
grid-column:4;
}
<div class="box">
<h4>HELLO</h4>
<div class="flexbox">
<button class="active">ONE</button>
<button>TWO</button>
<button>THREE</button>
</div>
</div>
<div class="box">
<h4>HELLO</h4>
<div class="flexbox">
<button >ONE</button>
<button class="active">TWO</button>
<button>THREE</button>
</div>
</div>
<div class="box">
<h4>HELLO</h4>
<div class="flexbox">
<button >ONE</button>
<button >TWO</button>
<button class="active">THREE</button>
</div>
</div>

Flex child of child does not expand to 100%

In CSS, if a child of a child is set to width: 100% and the wrapping div has display: flex set, the content does not expand to 100% it only uses the space of the content.
How would one make it expand to the size the grandchild sets itself but still use flex?
flex-grow is probably not the answer since this will always expand to take up the full space and not respect the size the grandchild sets itself.
See following example:
.wrapperFlex, .wrapperBlock{
border: 1px solid silver;
}
.wrapperFlex {
display: flex;
}
.levelOne {
}
.levelOneGrow {
flex-grow: 1;
}
.levelTwo, .levelTwoFullWidth {
color: white;
background-color: blue;
}
.levelTwoFullWidth {
width: 100%;
}
.levelOnePassthrough{
display: contents;
}
<!-- Premise -->
<div class="wrapperFlex">
<div>PRE</div>
<div class="levelOne">
<div class="levelTwoFullWidth">
WRAPPER FLEX
</div>
</div>
<div>AFTER</div>
</div>
<br/>
<!-- Not what is wanted, the grandchild here does not actually expand to 100%
it should be only as wide as the content here -->
<div class="wrapperFlex">
<div>PRE</div>
<div class="levelOneGrow">
<div class="levelTwo">
WRAPPER FLEX GROW
</div>
</div>
<div>AFTER</div>
</div>
<br/>
<!-- What is wanted but not possible, display: contents is not commonly available -->
<div class="wrapperFlex">
<div>PRE</div>
<div class="levelOnePassthrough">
<div class="levelTwoFullWidth ">
WRAPPER FLEX PASSTHROUGH
</div>
</div>
<div>AFTER</div>
</div>
Can you set flex-basis to the child?
.wrapperFlex, .wrapperBlock{
border: 1px solid silver;
}
.wrapperFlex {
display: flex;
}
.wrapperBlock {
display: block;
}
.levelOne {
flex-basis: 100%; /* Set flex-basis to 100% */
}
.levelTwo {
color: white;
width: 100%;
background-color: blue;
}
<div class="wrapperFlex">
<div class="levelOne">
<div class="levelTwo">
WRAPPER FLEX
</div>
</div>
</div>
<br/>
<div class="wrapperBlock">
<div class="levelOne">
<div class="levelTwo">
WRAPPER BLOCK
</div>
</div>
</div>
set .levelOne {width:100%} ,if im not misunderstanding you.
You need to add the flex property as one to the child i.e levelOne like this flex:1;.
It will work properly as you check here.
.wrapperFlex, .wrapperBlock{
border: 1px solid silver;
}
.wrapperFlex {
display: flex;
}
.wrapperBlock {
display: block;
}
.levelOne {
flex:1;
}
.levelTwo {
color: white;
width: 100%;
background-color: blue;
}
<div class="wrapperFlex">
<div class="levelOne">
<div class="levelTwo">
WRAPPER FLEX
</div>
</div>
</div>
<br/>
<div class="wrapperBlock">
<div class="levelOne">
<div class="levelTwo">
WRAPPER BLOCK
</div>
</div>
</div>

How do I correctly nest a flexbox to achieve a form layout?

I am looking to achieve the following layout:
Here is how I'm picturing it (with grids):
Black bar is the nav (we can ignore this)
A title and subtitle (purple) - these should be aligned and take up approx 70% of width - I think I've done this
A form which has 3 columns (should take up 70ish percent of the 70%, I don't want inputs to be too wide)
Column 1: Heading + text pairs
Column 2: it will have some icon/character - these must be perfectly aligned
Column 3: Heading + input boxes - these must be the same width
Here is my starting HTML:
.title-container {
display: flex;
justify-content: center;
background: red;
}
.title-item {
flex-basis: 75%;
}
.data-container {
display: flex;
justify-content: center;
background: blue;
}
.column-items {
flex-basis: 70%;
display: flex;
flex-direction: row;
}
.column-1-item {
background: green;
flex-grow: 0.5;
}
.column-2-item {
background: yellow;
flex-grow: 0.1;
align-self: center;
}
.column-3-item {
background: orange;
flex-grow: 1;
}
<div class="title-container">
<div class="title-item">
<h2>Title</h2>
<p>This is some text</p>
</div>
</div>
<div class="data-container">
<div class="column-items">
<div class="column-1-item">
<p>Heading1</p>
<p>SomeText</p>
</div>
<div class="column-2-item">
<p>--></p>
</div>
<div class="column-3-item">
<p>Heading1</p>
<input type="text" name="lname">
</div>
</div>
</div>
I have tried to expand on this, but no matter what I try, I end up further away from my design making me think there is something wrong with my initial design (and flex understanding). If I add additional 'row', it breaks my layout. I also think my data-container is wrongly setup, since this will take up far more space than I want it to
Here is a code pen.
Could someone help get me closer to my design?
I would wrap your entire html in a wrapper class so that you can get the general layout of the page like so:
<div class="wrapper">
<div class="title-container">
<h2>Title</h2>
<p>
Subtitle should be aligned with title
</p>
</div>
<div class="form-container">
<div class="item">
<div class="column">
<p>Heading1</p>
<p>Some Text</p>
</div>
<div class="column">
<p>-></p>
</div>
<div class="column">
<p>Heading1</p>
<p>[ input textfield ]</p>
</div>
</div>
<div class="item">
<div class="column">
<p>Heading3</p>
<p>Some Text</p>
</div>
<div class="column">
<p>-></p>
</div>
<div class="column">
<p>Heading2</p>
<p>[ input textfield ]</p>
</div>
</div>
<div class="item">
<div class="column">
<p>Heading3</p>
<p>Some Text</p>
</div>
<div class="column">
<p>-></p>
</div>
<div class="column">
<p>Heading3</p>
<p>[ input textfield ]</p>
</div>
</div>
<div class="item">
<div class="column"></div>
<div class="column"></div>
<div class="column submit-button">
<p>[ Button ]</p>
</div>
</div>
</div>
</div>
Then you can specify the width for the title-container and form-container with the width property. Making each of the item classes in the form container have a display: flex property lets you format the children column classes to have flex-grow: 1 so they can fill up the available space. The css then looks like:
.wrapper {
display: flex;
flex-direction: column;
align-items: center;
outline: 1px solid red;
}
.title-container {
width: 70%;
outline: 1px solid red;
}
.form-container {
width: 50%;
outline: 1px solid red;
}
.item {
display: flex;
outline: 1px solid red;
}
.column {
/* flex-grow: 1; */
flex: 1 1 0px;
outline: 1px solid red;
}
.submit-button {
display: flex;
align-items: flex-end;
justify-content: flex-end;
}
Alternately you can remove the flex-grow: 1 property from the column class and add justify-content: space-between to the item class to get a result similar to your example.
Here is the codepen.
Your .data-container just needs a flex-direction: column; because you want the .column-items to stack.

Layout a flex box similar to a table?

I'm working with a framework developed in-house which depends on a certain structure to our HTML. And one of the tricky things is that each row needs its own container with its own classes and data attributes.
So here's the problem. Without drastically changing the DOM, how can I make the flex box below render essentially like an HTML table would? Or is a table the only way? The solution will have to work in both IE11 and Chrome.
I'm trying to make it look like this...
Column A | Column B | Column C
1 | 2 | 3
section {
display: flex;
flex-wrap: wrap;
}
section .col {
flex: 1 1 auto;
}
section .line-break {
flex-basis: 100%;
width: 0px;
height: 0px;
overflow: hidden;
}
<html>
<head>
</head>
<body>
<section>
<header>
<div class="col">Column A</div>
<div class="col">Column B</div>
<div class="col">Column C</div>
</header>
<div class="line-break"></div>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
</section>
</body>
</html>
header, .row {
display: flex; /* aligns all child elements (flex items) in a row */
}
.col {
flex: 1; /* distributes space on the line equally among items */
}
<section>
<header>
<div class="col">Column A</div>
<div class="col">Column B</div>
<div class="col">Column C</div>
</header>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
</section>
If the content you are going to present is of type tabular data, then a table is the proper way.
HTML 5.1 W3C Recommendation, 1 November 2016, 4.9 Tabular data
Given that you can't, or don't want to, alter the markup, this can be done using CSS Table, and with that easily swap between any display type such as flex, block, etc., or even float, using media query etc.
I also removed the <div class="line-break"></div> element, since you don't need, though if it is rendered by a component or similar, leaving it as is won't cause any problem.
Using CSS Table
section {
display: table;
width: 100%;
}
section > * {
display: table-row;
}
section .col {
display: table-cell;
}
<html>
<head>
</head>
<body>
<section>
<header>
<div class="col">Column A</div>
<div class="col">Column B</div>
<div class="col">Column C</div>
</header>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
</section>
</body>
</html>
If you still need, or have to, use Flexbox, this answer of mine mention the difference between CSS Table and Flexbox on two important features:
Can flexbox handle varying sizes of columns but consistent row height?
Updated, a sample showing some useful Flexbox stuff, with varying width's and span columns.
Using Flexbox
.tbl {
display: flex;
flex-direction: column;
}
.row {
display: flex;
min-height: 50px;
}
.cell {
flex: 4;
border: 1px solid red;
}
.cell:nth-child(1) {
flex: 1;
}
.cell:nth-child(2) {
flex: 2;
}
.cell.span4-5 {
flex: 8 24px; /* col 4,5 flex-grow/border/padding */
}
.cell.span3-4 {
flex: 8 24px; /* col 3,4 flex-grow/border/padding */
}
.cell.span3-5 {
flex: 12 36px; /* col 3,4,5 flex-grow/border/padding */
}
.row:first-child .cell {
display: flex;
justify-content: center; /* center horiz. */
align-items: center; /* center vert. */
}
.row .cell {
padding: 5px;
box-sizing: border-box;
}
<div class="tbl">
<div class="row">
<div class="cell">ID </div>
<div class="cell">Nr </div>
<div class="cell">Header 1 </div>
<div class="cell span4-5"> Header 2 </div>
</div>
<div class="row">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">Content</div>
<div class="cell">Content</div>
<div class="cell">Content</div>
</div>
<div class="row">
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell span3-5">Content</div>
</div>
<div class="row">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell span3-4">Content</div>
<div class="cell">Content</div>
</div>
</div>
This code works for me:
* {
box-sizing: border-box;
}
body, html {
height: 100%;
margin: 0;
}
#container {
width: 400px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
background-color: lightgrey;
padding: 10px;
}
.shelf {
flex: 1 1 auto;
width: 100%;
margin-bottom: 10px;
border: 1px solid black;
background-color: lightgreen;
display: flex;
flex-direction: row;
}
.shelf:last-child {
margin-bottom: 0;
}
.labelbox {
flex: 0 0 35%;
}
.valuebox {
flex: 0 0 65%;
}
<div id="container">
<div class="shelf">
<div class="labelbox">Name: </div> <div class="valuebox">Barry Carter</div>
</div>
<div class="shelf">
<div class="labelbox">DOB:</div><div class="valuebox">10/12/1980</div>
</div>
<div class="shelf">
<div class="labelbox">
Description:
</div>
<div class="valuebox">
This content goes on and on and will force the height to expand. And the label box to the left will
"move" with it. There need not be much of a relation other than that their parent div/flex-container is
getting taller as well.
</div>
</div>
<div class="shelf">
<div class="labelbox">Group:</div><div class="valuebox">Advanced</div>
</div>
<div class="shelf">
<div class="labelbox">End Date:</div><div class="valuebox">2020-09-20</div>
</div>
</div>
Use CSS Grid. You can style any table the way you like.
Keep in mind If your table is more than 700 rows, the fram rate will start to drop, no matter what js framework you use. react, angular, vue or vanila JS. the scrolling will get real laggy.
And the maximum you row can use is 1000. More than that the extra row will create bad graphic. But you wont reach 1000 anyway, because at 700th row, the scrolling speed, starts to get bad.
If somehow you need to display more than 1000 rows, you will visualized lib. Every js framework has a lib to do so. Basically, it will render the rows in the view port. The rows that not in the view port will not be rendered. They will only be rendered when user scrolls.
This is year 2021, chances you read this answer in the future, the browsers vendor might probably fix the performance of 1000 rows, they might even extend that limit. So try it out.

Right align out the Float Property

.header {
display: flex
}
.logo,
.contribute,
.class 1,
.class 2 {
display: inline-block;
margin: auto 0;
}
<header class="header">
<div class="logo">
</div>
<nav </nav>
<div class="contribute">
</div>
<div class="class 1">
</div>
<div class="class 2">
</div>
</header>
In this suppose .header has display: flex; set.
.logo, .contributor, .class 1, .class 2 has display: inline-block; set and are child to parent .header class, which is flex.
How can we make sure that the .class 1 and .class 2 are right aligned without using the flow property?
Use margin-left: auto; for class1
div,
nav {
display: inline-block;
}
.header {
display: flex;
justify-content: space-between;
}
<header class="header">
<div class="left">
<div class="logo">1</div>
<nav></nav>
</div>
<div class="contribute">2</div>
<div class="right">
<div class="class1">3</div>
<div class="class2">4</div>
</div>
</header>
Simply add margin-left: auto; to .class1 and it will push itself and .class2 to the right
I fixed your class names as CSS isn't happy with a class name of only one digit, like the 1 in class 1, so either remove the space (which I did in below sample) or add i.e. nr (nr1). Also, as the items in a flex container is flex items, the display: inline-block will have no effect.
.header {
display: flex
}
.class1 {
margin-left: auto;
}
<header class="header">
<div class="logo">
logo
</div>
<nav>
</nav>
<div class="contribute">contribute
</div>
<div class="class1">class 1
</div>
<div class="class2">class 2
</div>
</header>