pure css for styling an element that does not contain something - css

I'm wondering if it's possible to apply css to something that does not contain something.
For example,
I have a component that can either contain a h1 or an h1 and span:
<div class="block">
<h1> title </h1>
</div>
or
<div class="block">
<h1> title </h1>
<span> sub </span>
</div>
I know of the selected :not, but I believe this will affect all elements except the :not
If I wanted to do something like:
.block { display: flex }
.block:DoesNotContain(span) { align-items: center }
Is there such a way to do so?

I have found a solution, it's quite nice and simple:
We can define a baseline and instead of "DoesNotContain", include everything if it does contain we can remove via the :has selector
.block {
display: flex;
align-items: center;
}
.block:has(span) {
align-items: normal;
}
It's not exactly the same but it achieves the same results.

Related

How to target a deeply nested header element

I have a h3 tag which is deeply nested as follows and can't amend the component that contains
this styling.
Instead since I only have 1 h3 within this nest, trying to target it and amend its padding.
But this is not working. Can I know what I am doing wrong? I am doing something similar for another
div tag targeting the 6th position for that div. That works fine. Issue is with targetting this h3
tag. Tried adding !important to these styling which makes no diff. What am I doing wrong here?
This is the structure of the html currently.
// This is the only div I created passing in my custom styling and the component is wrapped within this.
<div className={styles.main}>
// all the following is coming from an external component I can't amend.
<div>
<div>
<div>
<div>
<span>some span text 1</span>
<div>some span text 2</div> <!-- also targetting this div and this works fine. See CSS below -->
</div>
<div></div>
</div>
</div>
<div>
<div>
<div>
<h3> <!-- This is the only h3 in entire nest -->
Some Random Text <!-- trying to give this a left padding -->
</h3>
</div>
</div>
</div>
</div>
</div>
My SCSS File
.main > div:nth-child(5) {
padding-top: 100px; // this works fine
}
// tried all the following. None of them works. I do not get the padding left 50px;
// The text is stuck to the left with no margin / padding.
.main > h3 {
padding-left: 50px !important; // Don't want to use !important. Tried with it just in case it works.
}
.main > h3:first-of-type {
padding-left: 50px !important; // Don't want to use !important. Tried with it just in case it works.
}
.main > h3:first-child {
padding-left: 50px !important; // Don't want to use !important. Tried with it just in case it works.
}
The problem is that you are using the direct descendant selector.
You are only selecting h3 elements that are direct children of .main
You need to modify your selector to select children/grandchildren/etc.
.main h3 {
...
}

Can I make a property to apply only to selected child elements?

Say for example I have the following code!
<div class="container">
<div class="container__first">I am a box maybe!</div>
<div class="container__second">I am a circle maybe!</div>
</div>
.container {
overflow: hidden; /*How can I make it so this property only applies to container__first but not
the second*/
}
you can do this with :nth-child(), select the div after .container with .container div and in the :nth-child() you can select wich child to select.
.container div:nth-child(1) {
overflow: hidden; /*How can I make it so this property only applies to container__first but not */
background: green; /* the second*/
}
<div class="container">
<div class="container__first">I am a box maybe!</div>
<div class="container__second">I am a circle maybe!</div>
</div>
edit the easiest way would be just styling on .container__first{} or .container .container__first{} if only selecting that child is what you need.
If you've already set the classes, container_first and container_second, you could just set different properties in the CSS. Just to make it simple, I'll make the text in first container bolded and the text in the second container italicized. See:
.container__first {
overflow: hidden;
font-weight: bold;
}
.container__second {
overflow: visible;
font-style: italic;
}
<div class="container">
<div class="container__first">I am a box maybe!</div>
<div class="container__second">I am a circle maybe!</div>
</div>
If you don't want to assign classes, there are a few other options. Like #ramon-de-vires said above, you could assign an :nth-child or :last-child node to the last child (or a specific child) in the CSS, as shown:
.container p {
overflow: hidden;
font-weight: bold;
}
.container p:last-child {
overflow: visible;
font-style: italic;
font-weight: normal;
}
<div class="container">
<p>I am a box maybe!</p>
<p>I am a circle maybe!</p>
</div>
Possibly the easiest way, though, is to utilize an !important declaration, which overrides and ignores subsequent styling rules in the CSS. Just add !important after the parameter of any property (but before the ;) to indicate that the values should supersede values defined elsewhere.

Using flex-wrap:wrap but having trouble using pseudo selectors to adjust position of last item

We have an odd number of items inside of a flex: flex-wrap container and at a certain resolution when they wrap the last of the items is over to the left but I want it to (continue to) be to the right.
I googled and found a resource discussing a similar issue at: https://haizdesign.com/css/flexbox-align-last-item-grid-left/
The ::after pseudo-element they applied to achieve this is:
.speakers::after {
content: '';
flex: auto;
}
So I tried to apply this knowledge, but instead use the ::before pseudo-element to try to move my last item over to the right, but I could not get it to work. Below is some HTML and CSS code followed by a link to the CodePen:
#container {
display: flex;
flex-wrap: wrap;
}
.el-width {
min-width: 40%;
}
.last-el::before {
content: '';
flex: auto;
}
<div id="container">
<div class="el-width">Foo</div>
<div class="el-width">Bar</div>
<!-- uncomment to move Baz under Bar
<div class="el-width last-el"> </div>
-->
<div class="el-width last-el">Baz</div>
</div>
https://codepen.io/dexygen/pen/ExaNZYv
As you can see in the HTML if you interpose an actual (empty) div, Baz gets moved under Bar. I've also been able to introduce an actual element in my application and it does likewise. However I'd like to know how or if it can be achieved using ::before
This would be a lot easier with CSS Grid. I leave this here as an alternative answer, in case it helps others.
#container {
display: grid;
grid-template-columns: 40% 40%;
}
.el-width {
border: 1px solid;
}
.last-el {
grid-column-start: 2;
}
<div id="container">
<div class="el-width">Foo</div>
<div class="el-width">Bar</div>
<!-- uncomment to move Baz under Bar
<div class="el-width last-el"> </div>
-->
<div class="el-width last-el">Baz</div>
</div>
Pseudo elements on a flex container are treated as flex items (source).
So the first problem is that the pseudo element in your code is applied to the flex item (.last-el). It needs to be applied to the flex container (#container).
Then, the default order matters. The ::before() pseudo is the first flex item, and an ::after() pseudo would be the last.
So, if you're going to use a pseudo element as a flex item, to bump over an inner item, you need to use the order property to re-arrange the visual order. (Incidentally, this obviates the need to choose between ::before() and ::after().)
#container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.el-width {
flex: 0 0 33.33%;
}
#container::before {
order: 1;
flex: 0 0 33.33%;
content: '';
}
.el-width:nth-child(-n+3) {
order: 0;
}
.el-width:nth-last-child(-n+2) {
order: 2;
}
<div id="container">
<div class="el-width">Item 1</div>
<div class="el-width">Item 2</div>
<div class="el-width">Item 3</div>
<div class="el-width">Item 4</div>
<div class="el-width">Item 5</div>
</div>
The pseudo element method you're describing in your question is explained here:
Properly sizing and aligning the flex item(s) on the last row
A description of the problem, along with potential solutions, can be found here:
Targeting flex items on the last or specific row
And a clean and efficient solution for handling this problem, using CSS Grid, is here:
Equal width flex items even after they wrap
Fixing this is simple and to do it, we use a pseudo element. Going back to our container, (in this case, my container has a class of .speakers)
So they applied the ::after to the container to create a last element, not they apply to the last element last-el. And they did that because they used justify-content: space-between to justify their items leads their last element to unexpected position, which seems to not be of your case. If you want to layout in 2 dimensions, CSS Grid is the best. If you want better browser compatible, then you might already have the answer yourself in the codepen you gave. But I think what you really want might just be the answer that you basically can't solve this by just adding styles to .el-width::before?

Best way to display span element on next line in mobile view

I am looking for the best solution to display these span elements here:
I tried the following:
.card {
.gallery-text {
display: flex;
// margin-left: 60px;
// display: block;
}
display: flex; is actually what is causing the link to rub up against the word View and to, but display: flex; is what helps the span element show up on the next line.
Does anybody have a better idea?
Simple Solution : Just use a <br> Tag.
<p> tags are called block level elements, and will skip lines automatically.
<p>some text</p>
<p>other stuff</p>
<span> tags are inline elements, and will not break lines (skip line) unless they are told to with a <br/> tag.
<span>some text</span>
</br>
<span>other stuff </span>
alternatively, in the example provided, you can use to force a “non breaking space” character in between the link an text.
<span>...full gallery</a> to</span>
I ended up setting a display: flex; with flex-direction:row and justify-content:center; for the .gallery-text, in mixin, but then I had to go to .view-full-gallery and add a padding-left: 5px; and padding-right: 5px; and that seemed to do the trick.
Set a media query and add
span{
white-space: pre;
}

Flexbox on button parents do not work on on children psuedo selector content in mobile chrome/safari

This is a pretty specific problem... but flexbox rules don't seem to work on psuedo selector elements when the parent is a button in mobile safari and chrome.
Here is a codepen to clearly demonstrate this: http://codepen.io/anon/pen/zKaRXY
In desktop browsers, both blocks should have a "t" in the middle. In mobile browsers, only one has this "t" in the middle.
I have literally copy and pasted the full computed styles from the "div" to the "button" and it still fails for some reason.
<div class="container">
<button class="button">
<div class="child"></div>
</button>
<div class="button">
<div class="child"></div>
</div>
</div>
.container {
width: 900px;
margin: 50px auto;
font-family: "Arial", sans-serif;
}
.button {
display: flex;
align-items: center;
justify-content: center;
height: 300px;
background: #dbe8ff;
width: 500px;
}
.child:before {
content: "t";
flex: 0 1 auto;
background: #fff09b;
}
It's not just on mobile... Your current layout is never applying flex style to the pseudo elements.
The pseudo elements are children of the elemnt on wich they are declare. In this case, they are children of .child. So, they are grand-children of button, and your styles don't work.
If you want to style the pseudos this way, you have to set display: flex on child instead.
The reason that you see the t centered is because the dimension of child are adjusted to the dimension of the pseudo, and so this one can only be placed centered.
It seems, on your second time you have copied as<div class="button"> instead of <button class="button">

Resources