TL;DR:
Is it possible for css to ignore html element, but not its children?
Such element would be treated by css as if it wasn't there; but its children would be treated normally, i.e. as children of parent of the ignored element.
Details, Motivation:
Let's say we have a nice styled layout, e.g. with display: flex.
<div className="outer"><!-- this one has display: flex (just example) -->
<div className="inner">Foo</div>
<div className="inner">Bar</div>
<div className="inner">Baz</div>
<div className="inner">Foo 2</div>
<div className="inner">Bar 2</div>
<div className="inner">Baz 2</div>
</div>
But then, we need to wrap one group of our inner elements into form, or nav (for semantic or other reasons):
<div className="outer">
<div className="inner">Foo</div>
<div className="inner">Bar</div>
<div className="inner">Baz</div>
<form>
<div className="inner">Foo 2</div>
<div className="inner">Bar 2</div>
<div className="inner">Baz 2</div>
</form>
</div>
Well, of course this breaks our desired layout (e.g. flex), because <form> became the child of outer, and sibling of the first three inners.
Is it possible to make an element, in this case form, to be ignored by css - as if it wasn't there in the html element tree?
If it's not possible, has this feature ever been considered, worked on, rejected... ?
That's exactly what display:contents is designed to do. So:
form { display:contents }
.outer {
display: flex;
justify-content: space-evenly;
}
form {
display: contents;
}
<div class="outer">
<div class="inner">Foo</div>
<div class="inner">Bar</div>
<div class="inner">Baz</div>
<form>
<div class="inner">Foo 2</div>
<div class="inner">Bar 2</div>
<div class="inner">Baz 2</div>
</form>
</div>
just set the form to display: flex
now the form is a direct child... so you can for example set it to flex:1 or so.
and you will get a new "parent" for the form child elements.
Related
This question already has answers here:
Is there a way to remove a div but keep its elements?
(2 answers)
Closed 1 year ago.
I have a content management system that generates code like
<div class="container">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
</div>
and depending on the query it might also generate
<div class="container">
<div class="section">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
</div>
</div>
I want container be a flexbox container, and item be flexbox children in all cases.
Is there a way to unwrap the section element (=make the browser ignore this div layer - so that the item elements will be treated as if they where direct children of container)?
Or is that impossible with pure CSS?
You can do that like this:
.container, .container > .section {
display: flex;
...
}
.container > .item, .container > .section > .item {
...
}
It wouldn’t be a good idea to remove the section element because that is there for a reason. But the css above will take care of both cases.
You can add new rules for case when CMS creates additional tag and then add specificity them to increase chances that correct rule will be applied:
div.container div.section {
display: flex;
}
Read more about specificity here
As far as children elements are concerned, .section is a child element of .container and .item elements are children of .section. There isn't a way to ignore this via CSS.
I'd recommend you copy the styles of .container to .section and just make the necessary adjustments there.
It would help if you shared your current styles.
I'm having a text message wrapped in bootstrap column div and i'm trying to customize specific text in that column by wrapping it with another div but bootstrap pushes that text to a new line.
<div class="container">
<div class="row">
<div class="col">
Text1
</div>
<div class="col">Text2<div>Text3</div></div>
</div>
</div>
https://jsfiddle.net/e642tsb1/
Its because div has a default property of display: block; which makes the div appear in a new line. Use the bootstrap class d-inline-block to set its display: inline-block;
It will then appear in the same line.
.row {
background: white;
margin-top: 20px;
}
.col {
border: solid 1px red;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" rel="stylesheet" />
<div class="container">
<div class="row">
<div class="col">
Text1
</div>
<div class="col">Text2
<div class="d-inline-block">Text3</div>
</div>
</div>
</div>
Change your interior div to a span and it will appear on the same line:
<div class="container">
<div class="row">
<div class="col">
Text1
</div>
<div class="col">Text2 <span>Text3</span></div>
</div>
</div>
A div is a block level element by default, meaning its content will take the entire width of the page, so any child div will do the same. Here is your updated fiddle:
https://jsfiddle.net/2huy04kc/
That's true it will happen.
<div> Text2 </div> will push your <div> Text3 </div> to the next line as div are block elements.
A block-level element always starts on a new line and takes up the
full width available (stretches out to the left and right as far as it
can).
Better you use <span></span> or give a display: inline-block; property to the inner div containing Text3.
Learn different types of display in CSS here.
The div element is a block-level element. A block-level element always starts on a new line and takes up the full width available. You can use span element as an inline element. An inline element does not start on a new line and only takes up as much width as necessary.
Solution 1 : Replace div element with span element
<div class="container">
<div class="row">
<div class="col">
Text1
</div>
<div class="col">Text2<span>Text3</span></div>
</div>
</div>
Solution 2 : Styling div element to display as an inline element (not recommended).
<div class="container">
<div class="row">
<div class="col">
Text1
</div>
<div class="col">Text2<div style="display:inline">Text3</div></div>
</div>
</div>
Why is 100% width not applied in this implementation (where the class uk-width-1-1 is applied to nested div of child of grid container):
<div uk-grid>
<!-- column 01 -->
<div>
<!-- this will be a row, stacked -->
<div class="uk-width-1-1 mine">Row 01</div>
<!-- this will be a row, stacked -->
<div class="mine">Row 02</div>
</div>
</div>
However it is applied when implementing like this (where the class uk-width-1-1 is applied to child of grid container):
<div uk-grid>
<!-- column 01 -->
<div class="uk-width-1-1">
<!-- this will be a row, stacked -->
<div class="mine">Row 01</div>
<!-- this will be a row, stacked -->
<div class="mine">Row 02</div>
</div>
</div>
I can see how to achieve the effect I want, but would like to know what the logic is behind it so I can understand it better.
jsFiddle showing both implementations is here.
Edit:
I can replicate the behaviour using just flex styles - so I need to figure out why can child div be 100% and nested divs cannot?
<!-- nested div is only the width of the content -->
<div style="display:flex; flex-wrap: wrap">
<div>
<div style="width:100%; background: red">Item 1</div>
<div style="width:100%; background: red">Item 2</div>
</div>
</div>
<!-- if applied to child div, is 100% width of parent -->
<div style="display:flex; flex-wrap: wrap">
<div style="width:100%">
<div style="background: red">Item 1</div>
<div style="background: red">Item 2</div>
</div>
</div>
<!-- if not using flex at all, nested divs are 100% width of parent -->
<div>
<div>
<div style="width:100%; background: red">Item 1</div>
<div style="width:100%; background: red">Item 2</div>
</div>
</div>
Perhaps a flex item, which is any immediate child div in a flex container, by default is the width of its content, therefore nested divs, if given width: 100%, faithfully represent 100% of their immediate parent container's width and not the top level container where display: flex is defined?
Why does applying uk-width-1-1 effect child divs of uk-grid but not
nested divs of child?
Children of flex items is not part of the Flexbox. It is only children of a flex container (an element with display: flex) that is (or as you called them, immediate children), so your inner most div's is normal block level elements and will not respond to the set class uk-width-1-1, their parent will though, as in your second sample.
When it comes to Flexbox, one can, simplified, say they that the flex container behave similar to a block element and the flex item like a inline block.
This is also shown in your 1st replicated sample, where neither the flex item nor the inner most div's have a set width, so the inner most div's content will define the width of the flex item, in the same way a nested div in a div would, where the outer div is set to display: inline-block.
Here is some good resources:
https://www.w3.org/TR/css-flexbox-1/#box-model
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
Updated
Note, a flex item can at the same time also be a flex container, like in below sample
<div style="display:flex; flex-wrap: wrap">
<div style="display:flex; flex-wrap: wrap; flex-grow: 1; ">
<div style="flex-basis: 100%; background: red">Item 1</div>
<div style="flex-grow: 1; background: red">Item 2</div>
</div>
</div>
Given this html:
<div id="wrapper">
<div id="header-holder">
<div class="header">header 1</div>
<div class="header">header 2</div>
</div>
<div id="project">project data</div>
</div>
I want to apply a style to element in .header only if #project exists. I'd like to do this with css. Is this possible?
The trouble with cascading style sheets is they cascade. They go down layer by layer and don't come back up. If your structure were set where your <div id="project"> was above your <div id="header-holder"> you could use:
div#wrapper #project + #header-holder .header { ... }
However, if you are unable to restructure your HTML, then you'll need to use javascript. If you have access to jQuery you could try the following:
$('#wrapper:has(#project) .header').addClass("has_project");
Then in CSS:
.header.has_project{ ... }
I would like to build a sort of "stack" of divs (with class .inner) within a containing div (#container) where each inner is pushed as far down in the container as possible without overlapping another inner. I've included illustrations of what this would look like with one and three inners, respectively:
I know I could get the result on the left by setting...
#container { position: relative; }
.inner {
position: absolute;
bottom: 0;
}
...but this solution would not scale to the example on the right - instead it would cause all of the inners to overlap one another. Is there any good way to accomplish what I want through CSS alone for an arbitrary number of inners? I know I could do it with some hacky Javascript.
You could use an additional container for the inner containers and use the trick you suggested.
<style>
div{border:1px solid red}
#container{height:1000px;}
#inner-container{position:absolute;bottom:0px;}
.inner {height:200px;width:200px;margin:5px;;
</style>
<div id="container">
<div id="inner-container">
<div class="inner"></div>
<div class="inner"></div>
<div class="inner"></div>
</div>
</div>
Depends on what browsers you need to support. But a much cleaner solution would be to try mimicking some table layout in CSS.
I've not had a chance to thoroughly test this with IE8+, but most modern browsers can handle CSS table layout properties which would allow you to do something like this relatively easily.
So...
CSS
.container { display: table-cell; vertical-align: bottom; height: 400px}
HTML
<div class="container">
<div class="inner">1</div>
<div class="inner">2</div>
<div class="inner">3</div>
</div>
The only caveat is that if you have two of these "container" divs following each other in the code, than they will behave like table-cells (TDs) and sit next to each other.
If you want to stack them, then you can get around this by wrapping the containers in a div without the table-cell style, or sticking another element inbetween... e.g.
<div>
<div class"container">
<div class="inner">1</div>
<div class="inner">2</div>
<div class="inner">3</div>
</div>
</div>
<div>
<div class="container">
<div class="inner">1</div>
<div class="inner">2</div>
<div class="inner">3</div>
</div>
</div>
OR...
<div class="container">
<div class="inner">1</div>
<div class="inner">2</div>
<div class="inner">3</div>
</div>
<div></div>
<div class="container">
<div class="inner">1</div>
<div class="inner">2</div>
<div class="inner">3</div>
</div>