How to position this flexbox child depending on presence of another child? - html

I have a quick follow up to my earlier question posted here.
I'm trying to position a flexbox child element depending on whether another child is present or not.
Best visualised in this codepen
In some panels, ICON3 will not be loaded. The container receives a class of hidden and I can choose to hide it with display or opacity etc.
I'd like ICON4 to stay on the right, and to move up in line with ICON2, and for the wrapper to resize accordingly. But I can't seem to get it working.
What I've tried:
opacity: 0 - this keeps ICON4 on the right, but does not resize the wrapper, as ICON3 still exists and takes up space.
display: none - this just moves ICON4 to when ICON3 was.
Also tried styling combinations using .hidden + .four but I can't find a working solution.
Would appreciate any help!
Snippet below:
* {
font-family: sans-serif;
}
.wrapper {
display: flex;
align-items: flex-start;
width: 500px;
background-color: #F9F9F9;
padding: 10px;
position: relative;
margin-bottom: 2em;
}
.image {
width: 150px;
margin-right: 1em;
}
.row {
display: flex;
flex-direction: column;
flex: 1 0 0;
}
.more {
font-weight: bold;
margin-top: 1em;
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 4em;
justify-content: space-around;
}
.hidden {
opacity: 0;
/*display: none; // this pushes ICON4 underneath */
}
.hidden + .four {
/*margin-bottom: 1.4em; // this seems to position .four correctly, but doesn't alter height of .wrapper */
}
.four {
margin-top: auto;
}
.ideal {
position: absolute;
bottom: 20px;
right: -44px;
}
.ideal span {
color: green;
font-weight: bold;
opacity: .2;
margin-right: 4em
}
.ideal {
position: absolute;
bottom: 32px;
right: -201px;
}
.ideal span {
color: green;
font-weight: bold;
opacity: .2;
margin-right: 4em
}
<div class="wrapper">
<div class="image">
<img src="http://placehold.it/150x68" alt="" />
</div>
<div class="row">
<span>Text content</span>
<span>Text content</span>
<span>Text content</span>
<div class="more">
<span class="one">ICON1
</span>
<span class="two">ICON2</span>
<span class="three hidden">ICON3</span>
<span class="four">ICON4</span>
</div>
</div>
<div class="ideal"><span>ICON4</span>< ideal position and wrapper to resize</div>
</div>

I overlooked the height rule on .more
I don't think I change this with css as it's a parent, but with javascript I can add a class to .more and override the height.

Related

Cannot resize image in CSS because it overflows a <div>

I have the following code:
JavaScript:
import React, { useState } from "react";
import logo from "../Static/white_lotus.jpeg";
import "./LogoSearchProfile_Header.css";
function Header() {
return (
<div className="header">
<div className="header-left">
<div className="header-logo-link">
<img
className="header-logo"
src={logo}
alt=""
/>
</div>
</div>
</div>
);
}
export default Header;
LogoSearchProfile_Header.css:
.header {
display: flex;
align-items: center;
height: 60px;
position: sticky;
top: 0;
z-index: 100;
background-color: white;
border-bottom: 1px solid lightgray;
}
.header-left{
margin-left: 2%;
justify-content: space-between;
display: flex;
width: 50px;
height: inherit;
align-items: center;
background-color: red ;
}
.header-logo > img {
height: 20px;
}
where I'm using this image (white_lotus.jpeg) as my logo:
Currently, this produces:
where the <img> overflows the <div>, and despite everything I try, I can't change the size of the image. Altering the tag header-logo does nothing, it seems. Is there anything I can do? Why does this happen?
Your image itself has the class header-logo and your CSS is selecting its children with >. Try changing your CSS from .header-logo > img to .header-logo or just img.
.header {
display: flex;
align-items: center;
height: 60px;
position: sticky;
top: 0;
z-index: 100;
background-color: white;
border-bottom: 1px solid lightgray;
}
.header-left{
margin-left: 2%;
justify-content: space-between;
display: flex;
width: 50px;
height: inherit;
align-items: center;
background-color: red ;
}
.header-logo {
height: 20px;
}
<div class ="header">
<div class ="header-left">
<div class ="header-logo-link">
<img class ="header-logo"
src=https://i.stack.imgur.com/CSimC.jpg
alt=""/>
</div>
</div>
</div>
Using .header-logo > img is instructing the browser to look at the child of header-logo which in fact there is none.
Your height: 20px is essentially calling to both the image and the class associated with it, which is unnecessary. I would suggest using one or the other, like below.
EDIT ~ you can also use a negative z-index or overflow-y: hidden; to have the overflow of the image appear behind the div. So it doesn't appear to be "larger" anymore.
.header {
display: flex;
align-items: center;
height: 60px;
position: sticky;
top: 0;
z-index: 100;
background-color: white;
border-bottom: 1px solid lightgray;
}
.header-left {
margin-left: 2%;
justify-content: space-between;
display: flex;
width: 50px;
height: inherit;
align-items: center;
background-color: red;
}
.header-logo {
height: 20px;
}
/* img {
height: 20px;
} */
<div className="header">
<div className="header-left">
<div className="header-logo-link">
<img class="header-logo" src="https://i.ibb.co/3WWwMHR/CSimC.jpg" alt="" />
</div>
</div>
</div>
Overflow happens when content exceeds parent height. Make content height match parent/container height, or do not set height with arbitrary fixed measurements.
I think what you are trying to do is the following:
.header-left > img {
height: 20px;
}
Or
.header-logo {
height: 20px;
}
As the img's class is header-logo and the selecter > means an img whose parent has class header-logo which is not the case here.

Creating responsive CSS scoreboard with numeric values immediately to the left of bars

I'm trying to write a simple, responsive scoreboard with HTML and CSS. For each player (three total), there will be a bar (a div with a height, width, and background-color), and a numeric score immediately to the right of the bar.
I wish for the bars to be in a column flex container. The topmost bar will always take up the full width of the flex container. The width of the second two bars could then be set relative to that of the first bar. If the second player scored half as much as the first, the width of their bar would be set to 50%.
Is it possible to use this approach while also positioning the numeric scores immediately to the right of the bars? I previously tried keeping each bar in a div with its corresponding numeric score, but it became very difficult to set the width of the bars accurately.
Here's the code I have right now:
span {
font-family: Arial, sans-serif;
color: #7B7B7B;
}
#container {
height: 100%;
width: 100%;
display: flex;
}
#names {
padding-right: 2%;
display: flex;
flex-direction: column;
}
#player1name, #player2name, #player3name {
font-weight: bold;
height: 2em;
line-height: 2em;
}
#bars {
flex: 1;
display: flex;
flex-direction: column;
}
#player1bar, #player2bar, #player3bar {
height: 2em;
flex: 1;
}
#player1bar {
background-color: #4776d2;
width: 100%;
}
#player2bar {
background-color: #2a85b6;
width: 50%;
}
#player3bar {
background-color: #51636d;
width: 7.5%;
}
#scores {
padding-left: 2%;
display: flex;
flex-direction: column;
}
#player1score, #player2score, #player3score {
height: 2em;
line-height: 2em;
font-weight: bold;
text-align: left;
}
<body>
<div id="container">
<div id="names">
<span id="player1name">Alice</span>
<span id="player2name">Bob</span>
<span id="player3name">Charlie</span>
</div>
<div id="bars">
<div id="player1bar"></div>
<div id="player2bar"></div>
<div id="player3bar"></div>
</div>
<div id="scores">
<span id="player1score">10,000</span>
<span id="player2score">5,000</span>
<span id="player3score">750</span>
</div>
</div>
</body>
Do you mean something kind of this?
span {
font-family: Arial, sans-serif;
color: #7B7B7B;
}
#container {
height: 100%;
width: 100%;
display: flex;
}
#names {
padding-right: 2%;
display: flex;
flex-direction: column;
}
#player1name, #player2name, #player3name {
font-weight: bold;
height: 2em;
line-height: 2em;
}
#bars {
flex: 1;
display: flex;
flex-direction: column;
}
#player1bar, #player2bar, #player3bar {
height: 2em;
flex: 1;
}
#player1bar {
background-color: #4776d2;
width: 100%;
}
#player2bar {
background-color: #2a85b6;
width: 50%;
}
#player3bar {
background-color: #51636d;
width: 7.5%;
}
#scores {
padding-left: 2%;
display: flex;
flex-direction: column;
}
#player1score, #player2score, #player3score {
height: 2em;
line-height: 2em;
font-weight: bold;
text-align: left;
}
.bars {
width: 90%;
}
.bar {
position: relative;
}
.bar span {
position: absolute;
top: 50%;
transform: translateY(-40%);
left: 100%;
padding-left: 10px;
}
<div id="container">
<div id="names">
<span id="player1name">Alice</span>
<span id="player2name">Bob</span>
<span id="player3name">Charlie</span>
</div>
<div class="bars">
<div class="bar" id="player1bar">
<div></div>
<span id="player1score">10,000</span>
</div>
<div class="bar" id="player2bar">
<div></div>
<span id="player2score">5,000</span>
</div>
<div class="bar" id="player3bar">
<div></div>
<span id="player3score">750</span>
</div>
</div>
</div>
I changed the html structure a bit because the your one wasn't easy to remake.
One tip, use more classes rather than id's. It is easier to write css for classes.

Is it possible to align one flex child above another flex child in a line below?

I am struggling with a flexbox tag here. I have a page header, that consists from two parts: smaller text "A comprehensive manual:" and "How to take a dog from UK to SOME OTHER COUNTRY".
So the problem is, according to design document, "How to take a dog from UK to SOME OTHER COUNTRY" should be centred, but "A comprehensive manual" line shouldn't, it should start right above letter "H" in the second line, "How to take...", as shown on a picture below:
here
Obviously, when I resize a window, flexbox starts doing it thing and wars text around, changing the position of the "How", however "A comprehensive manual" should also move to keep along.
Is it possible with a flexbox, or I should use ::after pseudoelement to achieve it? Or maybe there is better solution?
Code is below, there is also a link to the codepen with an example.
Many thanks!
<div class="take-where-box">
<div class="flex">
<div class="take-where-box__text-block large" id="take-where-box__text-block-intro"><p class="take-where-box__small-text">A Comperhensive Manual:</p></div>
<div class="take-where-box__text-block" id="take-where-box__text-block-1"><p>How to take a dog</p></div>
<div class="take-where-box__text-block" id="take-where-box__text-block-2"><p>from UK</p></div>
<div class="take-where-box__text-block" id="take-where-box__text-block-3">
<div class="select-box">
/*code for select box*/
</div> <!-- end of select-box-->
</div>
</div>
</div> <!-- take-where-box-->
Full codepen is here:
https://codepen.io/abby97/pen/oNYjrpV
Perhaps the layout can be achieved with a minor adjustment to the align-items property and a pseudo element.
.flex {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: flex-end; /* changed from baseline */
}
#take-where-box__text-block-1::before {
font-size: 70%;
content: "A Comprehensive Manual:";
}
#take-where-box__text-block-1::before {
font-size: 70%;
content: "A Comprehensive Manual:";
}
body,
html {
margin: 0;
padding: 0;
font-family: 'Calibri', serif;
font-size: 100%;
color: black;
background-color: var(--cyan-superdark);
}
.container {
background-color: var(--main_color);
margin: 0 auto;
width: 80%;
}
.header,
.content {
margin: 0;
display: flex;
flex-direction: column;
align-items: center;
}
.header {
background-color: var(--yellow-main);
}
.content {
background-color: var(--cyan-superdark);
}
.take-where-box {
font-size: 3rem;
justify-content: center;
align-items: center;
font-weight: bold;
width: 90%;
border: 0.4rem solid black;
padding: 1.5rem;
}
.flex {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: flex-end;
}
.take-where-box__small-text {
font-size: 70%;
margin: 0;
}
.take-where-box__text-block {
flex-basis: 1;
/* flex-shrink: 0; */
/* min-width: min-content; */
padding: 0 0.5rem;
}
.large {
flex-basis: 100%;
}
.take-where-box__text-block>p {
margin: 0;
}
/*select-box - a custom select box, taken from https://www.youtube.com/watch?v=k4gzE80FKb0 */
.select-box {
display: flex;
flex-direction: column;
position: relative;
width: 22rem;
}
.select-box__selected-option,
.select-box__options-container {
border: 0.4rem solid black;
}
.select-box .select-box__options-container {
max-height: 0;
opacity: 0;
transition: all 0.3s;
/* what are other options? */
order: 1;
}
.select-box__selected-option {
margin-bottom: 8px;
position: relative;
order: 0;
}
.select-box__options-container {
position: absolute;
box-sizing: border-box;
/*otherwise border will add up to the witdh of this element making it bigger than parent, BAD!*/
width: 100%;
top: 7.5rem;
background-color: white
}
.select-box__selected-option::after {
content: "";
background: url("assets/arrow-down.svg");
background-size: contain;
background-repeat: no-repeat;
position: absolute;
height: 100%;
width: 3.0rem;
/* height: 4rem; */
right: 1rem;
top: 1rem;
transition: all 0.4s;
}
.select-box .select-box__options-container.active+.select-box__selected-option::after {
transform: rotateX(180deg);
top: -1rem;
}
.select-box .select-box__options-container.active {
max-height: min-content;
opacity: 1;
}
.select-box .select-box__option,
.select-box__selected-option {
padding: 0.5rem 1rem;
cursor: pointer;
}
.select-box .select-box__option:hover {
background-color: blue;
}
.select-box label {
cursor: pointer;
}
.select-box .select-box__option .radio {
display: none;
}
<div class="container">
<div class="take-where-box">
<div class="flex">
<div class="take-where-box__text-block large" id="take-where-box__text-block-intro">
<!--<p class="take-where-box__small-text">A Comperhensive Manual: </p>-->
</div>
<div class="take-where-box__text-block" id="take-where-box__text-block-1">
<p>How to take a dog</p>
</div>
<div class="take-where-box__text-block" id="take-where-box__text-block-2">
<p>from UK</p>
</div>
<div class="take-where-box__text-block" id="take-where-box__text-block-3">
<div class="select-box">
<div class="select-box__options-container">
<div class="select-box__option">
<input type="radio" class="radio" id="US" name="category">
<label for="US">to US</label>
</div>
<div class="select-box__option">
<input type="radio" class="radio" id="EU" name="category">
<label for="EU">to EU</label>
</div>
</div>
<!-- end of select-boxoptions-container-->
<div class="select-box__selected-option">
to US
</div>
</div>
<!-- end of select-box-->
</div>
</div>
</div>
<!-- take-where-box-->
</div>
revised codepen
i believe your code is unnecessery overcomplicated.
element positioning like in image you can achieve with this piece of code. please note that css is inline, because this is just a guidline, you can adapt it by your needs:
<div style="display:flex; align-items:center; flex-direction:column">
<div>
<div>
<p>A Comperhensive Manual:</p>
</div>
<div style="display:flex">
<p>How to take a dog from UK</p>
<p>selectbox</p>
</div>
</div>
</div>

How to position absolute element vertically in the center?

As you can see in the snippet below, I have a .square-container which is positioned absolutely and it contains a square. I'm trying to vertically position the .square-container in the center of the parent div.
.container {
position: relative;
background-color: blue;
}
.square-container {
position: absolute;
top: 0;
right: 0;
height: 30px;
width: 30px;
}
.square {
width: 100%;
height: 100%;
background-color: red;
}
.hello {
padding: 15px;
}
<div class='container'>
<p class='hello'>Hello</p>
<div class="square-container">
<div class='square'></div>
</div>
</div>
For positioning absolute elements in the middle use top: 50%
And then use transform: translateY(-50%); and its centered
.container {
position: relative;
background-color: blue;
}
.square-container {
position: absolute;
right: 10px;
top: 50%;
height: 30px;
width: 30px;
transform: translateY(-50%);
}
.square {
width: 100%;
height: 100%;
background-color: red;
}
.hello {
padding: 15px;
}
<div class='container'>
<p class='hello'>Hello</p>
<div class="square-container">
<div class='square'></div>
</div>
</div>
.container{
display:flex;
align-items:center;
}
You wouldn't need absolute positioning here. If you set the container as a flex wrapper, you won't also need to position it relatively and can get rid of the square-container div as well that currently wraps the div.square element.
To push the square to the right, we could
A) use auto-margins inside the flex layout. So all that our div.square needs, is margin-left: auto, which tells the browser to push it as far as possible from its left siblings.
B) Use justify-content: space-between on our container. This tells the flex container to space out the elements to the sides.
The approaches differ very slightly and don't really matter in this example until we start adding more elements.
An updated example:
A
.container {
display: flex;
align-items: center;
background-color: skyblue;
padding: 15px;
}
.square {
height: 30px;
width: 30px;
margin-left: auto;
background-color: tomato;
}
<div class='container'>
<p class='hello'>Hello</p>
<div class='square'></div>
</div>
B
.container {
display: flex;
align-items: center;
justify-content: space-between;
background-color: skyblue;
padding: 15px;
}
.square {
height: 30px;
width: 30px;
background-color: tomato;
}
<div class='container'>
<p class='hello'>Hello</p>
<div class='square'></div>
</div>

How to layer shapes in flexbox

I am currently using this solution for modified for my use case specifically here. When I originally saw the design I figured that I would make two divs inside one flexbox container, the div on the right would be z index'd above the one on the right. Something like...
.container {
display: flex;
width: 200px;
flex-direction: row;
}
.left-side {
flex: 4;
background-color: red;
}
.right-side {
flex: 1;
background-color: orange;
z-index: 3;
border-style: 2px solid white;
border-radius: 50%;
}
<div class="container">
<div class="left-side">
View Cart
</div>
<div class="right-side">
3
</div>
</div>
This doesn't layer my elements on top of one another at all because they are positioned next to each other. So my question is:
How can I use make a layered layout while still taking advantage of all the nice positioning flexbox allows without the position absolute / position relative solution that I'm hacking together? Or, is this position absolute / relative the correct way to solve my problem?
You can apply the red background to the container, and use transform: translateX(50%) to move the orange circle half way outside of the container to pull off that effect.
.container {
display: flex;
width: 200px;
flex-direction: row;
background: red;
position: relative;
color: white;
}
.container:before {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
content: '';
}
.container:before,
.count {
border: 2px solid white;
}
.left-side {
flex-grow: 1;
}
.center {
display: flex;
justify-content: center;
align-items: center;
}
.count {
width: 50px;
height: 50px;
background-color: orange;
border-radius: 50%;
transform: translateX(50%);
}
<div class="container">
<div class="left-side center">
View Cart
</div>
<div class="right-side">
<div class="count center">3</div>
</div>
</div>
Negative margins
You can use negative margins to solve the problem without using position absolute/relative solution.
.container {
display: flex;
width: 200px;
flex-direction: row;
}
.left-side {
flex: 4;
background-color: red;
}
.right-side {
flex: 1;
background-color: orange;
z-index: 3;
border-style: 2px solid white;
border-radius: 50%;
margin-left: -60px;
text-align: center;
}
<div class="container">
<div class="left-side">
View Cart
</div>
<div class="right-side">
3
</div>
</div>