How do I get flex elements not to grow on click? - html

Hobbyist who really sucks at css.
I have the following three divs:
The problem is, when I click on the middle one, the box grows, and so do the other two boxes:
How do I make boxes start off and stay the same size even after click. The reason the box is growing is do to adding the "arrow-icon"
Code looks like this:
HTML
<section class='modes-flex__options'>
<div class='options'>
<h2 class='options__title'>Options</h2>
<div class='options__item-container'id='1v1' onClick="selectedGameOption(this.id)">
<h3 class='options__item'>Player vs AI (1 v 1) </h3>
<div class='arrow-icon__div'>
<i></i>
</div>
</div>
<div class='options__item-container' id='1v1-tourny' onClick="selectedGameOption(this.id)">
<h3 class='options__item'>Player vs AI (Tournament)</h3>
<div class='arrow-icon__div'>
<i></i>
</div>
</div>
<div class='options__item-container' id='ai-v-ai-tourny' onClick="selectedGameOption(this.id)">
<h3 class='options__item' >AI vs AI (Tournament)</h3>
<div class='arrow-icon__div'>
<i></i>
</div>
</div>
</div>
</section>
CSS
.modes-flex{
display: flex;
margin-top: 3rem;
&__options{
flex:1;
display: flex;
justify-content: end;
}
&__description{
flex:1;
display: flex;
flex-direction: column;
}
}
.options{
margin-right: 5rem;
&__title{
font-size: 1.2rem;
padding-bottom:2rem;
}
&__item{
flex: 1;
padding-right: 5rem;
}
}
.description{
&__title{
font-size: 1.2rem;
padding-bottom:2rem;
}
}
.options__item-container {
padding: 1.5rem 1rem 1.5rem 1rem;
margin-bottom: 2rem;
box-shadow: 0 0 10px lightgrey;
border: 1px solid lightgrey;
display: flex;
align-items: center;
&:hover{
cursor: pointer;
}
}
.arrow-icon__div{
text-align: right;
}
.active-option{
background-color: $dark-navy;
color: white;
}
Tried to set min and max width and was still growing , just want them to stay even width after adding the icon.

You said it: The reason the box is growing is do to adding the "arrow-icon".
In my experience, in these situations, I always added to the default size of the boxes so that when another element (i.e. arrow-icon) is added, it doesn't change the size. (Because there is enough space in the box for arrow-icon to be added). With doing so, all the boxes remain the same through any actions.

Related

How to fill remaining space on last line for wrapped text?

I'm trying to create a webapp where I need to render user entered title and content. I'd like to render all the action buttons related to the title on the same line as the last word of the title ("displays" in the demo) if the action bar fits, or on the next line if there's not enough space to fit whole action bar on the same line.
I've created a demo which results in correct rendering here: https://jsfiddle.net/mtrantalainen/h6qyv7a4/1/
(Note how this results in nice rendering in all cases, including the case where everything fits on one line on wide display, all to the way to case where buttons barely fit on a single line alone. I've tested the demo with Chrome and Firefox only.)
Same demo here inline:
header
{
display: flex;
flex-wrap: wrap;
gap: 0.5em;
}
header > span /* I would like to h1 here instead */
{
font-size: 2rem;
outline: dotted 1px #ddd;
}
.buttons
{
display: flex;
flex: 1 0 auto;
flex-wrap: nowrap;
}
.buttons a
{
display: flex;
align-items: center;
justify-content: center;
min-width: 44px;
min-height: 44px;
flex: 0 0 auto;
padding: 0.5rem;
box-sizing: border-box;
border: solid red 1px;
cursor: pointer;
}
.buttons .fill
{
flex: 1 0 auto;
background: yellow;
}
<header>
<span>Here's</span> <span>lots</span> <span>of</span> <span>text</span> <span>as</span> <span>a</span> <span>header</span> <span>which</span> <span>cannot</span> <span>easily</span> <span>fit</span> <span>on</span> <span>one</span> <span>line</span> <span>on</span> <span>most</span> <span>displays</span>
<div class="buttons">
<a>1</a>
<a>2</a>
<a>3</a>
<span class="fill"></span>
<a>4 with long label</a>
<a>5</a>
</div>
</header>
Screenshot (this is also the rendering I want):
The intent is to keep all the action buttons with red borders on the same line and fit the whole action button block on the line with the last word of the title, if possible. The yellow area in the middle of action bar would be transparent filler with zero or more pixels and allows positioning selected actions near the title or the right margin if there's extra space on line.
The demo works by wrapping every word in the title as a separate <span> element and flex-wrap is used to allow title to wrap and the action bar to follow on the same line.
However, this doesn't allow semantic markup because I cannot even wrap all the words in an <h1> element. In addition, the current demo doesn't play nicely with copy-pasting the title because every word will end up on separate line if copied.
Can anybody suggest any way to result in similar rendering using only HTML5 and CSS given following markup?
<header>
<h1>Here's lots of text as a header which cannot easily fit on one line on most displays</h1>
<nav class="actions">
<a>1</a>
<a>2</a>
<a>3</a>
<span class="fill"></span>
<a>4 with long label</a>
<a>5</a>
</nav>
</header>
Another possibility for the actions markup in semantic way would be
<div class="actionbar">
<nav class="titleactions">
<a>1</a>
<a>2</a>
<a>3</a>
</nav>
<nav class="extraactions">
<a>4 with long label</a>
<a>5</a>
</nav>
</div>
with the whole <header> as above. I used span.fill in the demo because it was easiest to implement and doesn't mess with the semantics too bad.
I am not sure that I understood your question well but is that what you are looking for?
header
{
display: flex;
gap: 0.5em;
}
header > h1/* I would like to h1 here instead */
{
font-size: 2rem;
outline: dotted 1px #ddd;
}
.buttons
{
display: flex;
flex: 1 0 auto;
flex-wrap: nowrap;
width: 40%;
}
.spanDiv { width: 60%}
.buttons a
{
display: flex;
align-items: center;
justify-content: center;
min-width: 44px;
min-height: 44px;
flex: 0 0 auto;
padding: 0.5rem;
box-sizing: border-box;
border: solid red 1px;
cursor: pointer;
}
.buttons .fill
{
flex: 1 0 auto;
background: yellow;
}
<header>
<div class="spanDiv">
<h1>Here's lots of text as eader which cannot easily fit on one lineon most displays</h1>
</div>
<div class="buttons">
<a>1</a>
<a>2</a>
<a>3</a>
<span class="fill"></span>
<a>4 with long label</a>
<a>5</a>
</div>
</header>
The least bad implementation I can figure out:
header
{
display: flex;
flex-wrap: wrap;
gap: 0.5em;
}
header > h1
{
display: contents;
}
header > span
{
font-size: 2rem;
outline: dotted 1px #ddd;
}
.buttons
{
display: flex;
flex: 1 0 auto;
flex-wrap: nowrap;
}
.buttons a
{
display: flex;
align-items: center;
justify-content: center;
min-width: 44px;
min-height: 44px;
flex: 0 0 auto;
padding: 0.5rem;
box-sizing: border-box;
border: solid red 1px;
cursor: pointer;
}
.buttons .fill
{
flex: 1 0 auto;
background: yellow;
}
<header>
<h1><span>Here's</span> <span>lots</span> <span>of</span> <span>text</span> <span>as</span> <span>a</span> <span>header</span> <span>which</span> <span>cannot</span> <span>easily</span> <span>fit</span> <span>on</span> <span>one</span> <span>line</span> <span>on</span> <span>most</span> <span>displays</span></h1>
<div class="buttons">
<a>1</a>
<a>2</a>
<a>3</a>
<span class="fill"></span>
<a>4 with long label</a>
<a>5</a>
</div>
</header>
Problematic parts remaining:
Copy-paste is still broken (tested with Chrome only).
The display: contents browser support is still a bit poor.
Every word in the title still needs a separate wrapper <span> element.
Words in the title cannot ever hyphenate.
span.fill needed to introduce the space.

Listitem is truly centered and the other items are in flow around it [duplicate]

I'm trying to align a top menu which consists of 3 blocks of content.
What I'm trying to achieve is this:
block 1: left aligned
block 2: centered horizontally
block 3: right aligned
If all 3 blocks were the same size, I could use flexbox (as in the snippet), but they're not, so it doesn't produce the output I require.
Instead, flexbox puts equal space between the 3 blocks - resulting in the middle block being aligned off-center.
I was wondering if this could be achieved with flexbox, or if not, another solution. This needs to work robustly in production so a 'Grid' solution is not applicable as there is insufficient support.
.container {
margin: 20px 0;
}
.row {
background-color: lime;
display: flex;
justify-content: space-between;
}
.item {
background-color: blue;
color: #fff;
padding: 16px;
}
<div class="container">
<div class="row">
<div class="item">left, slightly longer</div>
<div class="item">center, this item is much longer</div>
<div class="item">right</div>
</div>
</div>
You can consider flex-grow:1;flex-basis:0% for the left and right elements then use text-align to align content inside. I have added an extra wrapper to keep the background only around the text.
The trick is to calculate the free space by removing only the middle content and split it equally to the left and right element.
.container {
margin: 20px 0;
padding-top:10px;
background:linear-gradient(#000,#000) center/5px 100% no-repeat; /*the center*/
}
.row {
background-color: lime;
display: flex;
color: #fff;
}
.item:not(:nth-child(2)) {
flex-basis: 0%;
flex-grow: 1;
}
.item:last-child {
text-align: right;
}
.item span{
background-color: blue;
display:inline-block;
padding: 16px;
border: 2px solid red;
box-sizing:border-box;
}
<div class="container">
<div class="row">
<div class="item"><span>left, slightly longer</span></div>
<div class="item"><span>center, this item is much longer</span></div>
<div class="item"><span>right</span></div>
</div>
</div>
You can also do the same by keeping the element close. Simply adjust text-align:
.container {
margin: 20px 0;
padding-top: 10px;
background: linear-gradient(#000, #000) center/5px 100% no-repeat; /*the center*/
}
.row {
background-color: lime;
display: flex;
color: #fff;
}
.item:not(:nth-child(2)) {
flex-basis: 0%;
flex-grow: 1;
}
.item:first-child {
text-align: right;
}
.item span {
background-color: blue;
display: inline-block;
padding: 16px;
border: 2px solid red;
box-sizing: border-box;
}
<div class="container">
<div class="row">
<div class="item"><span>left, slightly longer</span></div>
<div class="item"><span>center, this item is much longer</span></div>
<div class="item"><span>right</span></div>
</div>
</div>
I asked what seems to be a very similar question and stack overflow directed me here. The response from #Paolamoralesval inspired me to realise the required effect can be achieved in CSS grid. Now that grid support is pretty much universal I hope that this meets everyone's needs. This solution is I believe fully responsive to window size as well as height and width of the header items as you should see if you resize the window where you view the snippet.
.header {
grid-row: 1;
grid-column: 1;
display: grid;
grid-template-rows: min-content;
grid-template-columns: 1fr 1fr 1fr;
}
.header-left {
justify-self: start;
align-self: center;
text-align: left;
background-color: red;
}
.header-center {
justify-self: center;
align-self: center;
text-align: center;
background-color: green;
}
.header-right {
justify-self: end;
align-self: center;
text-align: right;
background-color: blue;
}
.shrink-kitty {
width: 200px;
}
<html>
<body>
<div class="page">
<div class="header">
<div class="header-left">
<img class="shrink-kitty" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/bb/Kittyply_edit1.jpg/1280px-Kittyply_edit1.jpg"/><br/>
By David Corby<br/>
Edited by: Arad<br/>Image:Kittyplya03042006.JPG<a><br/><a href="https://creativecommons.org/licenses/by/2.5" title="Creative Commons Attribution 2.5">CC BY 2.5, Link
</div>
<div class="header-center">In the middle</div>
<div class="header-right">
Much much much much more on the right hand side</br>
Indeed two lines
</div>
</div>
<div class="body">Body of the page</div>
<div class="footer">At the bottom</div>
</div>
</body>
</html>
can you give flex-grow:1 for the item class and check
.item {
background-color: blue;
color: #fff;
padding: 16px;
flex-grow:1;
}
Hope this is what you are looking for
Alternative using display table (an ancient supported grid).
Quote from https://www.w3schools.com/cssref/pr_tab_table-layout.asp
If no widths are present on the first row, the column widths are divided equally across the table, regardless of content inside the cells
.container {
display: table;
table-layout: fixed
} // would divide cells equally along table's 100% width.
.row {
display: table-row
}
.item {
display: table-cell
}

Trying to make div height based on max content with flexbox and css font-size is ruining flex: auto

I have a flex container with multiple flex items, 2 of which I need to flex grow based on the text so all divs space out the same way.
I was able to accomplish this like this:
<div class="outer product-grid">
<div class="inner product-component">
<a class="image"><img class="product-image" /></a>
<a class="upper-text title">
Short Upper Text
</a>
<div class="lower-text author">
Short Lower Text
</div>
<h5 class="price"> <span>price</span> </h5>
</div>
<div class="inner">
<a class="image"><img class="product-image" /></a>
<a class="upper-text">
Long Upper Text - Long Upper Text
</a>
<div class="lower-text">
Long Lower Text - Long Lower Text
</div>
<h5 class="price"> price </h5>
</div>
<div class="inner">
<a class="image"><img class="product-image" /></a>
<a class="upper-text">
Even Longer Upper Text - Even Longer Upper Text
</a>
<div class="lower-text">
Even Longer Lower Text - Even Longer Lower Text
</div>
<h5 class="price"> price </h5>
</div>
</div>
SCSS
.outer {
display: flex;
flex: wrap;
.inner {
border: 5px solid yellow;
display: flex;
text-align: center;
margin-right: 1em;
margin-bottom: 1.5em;
width: 200px;
flex-direction: column;
font-size: 1.00em;
a.image{
border: 5px solid orange;
img {
width: em(160px);
height: em(210px);
}
}
a.upper-text {
border: 5px solid red;
flex: auto;
margin: 0.2em auto;
line-height: normal;
}
.lower-text {
border: 5px solid green;
flex: auto;
}
}
}
My upper-text and lower-text need to be different sizes. When I put a font-size into either of those classes, I lose the whole flex grow.
You can try on my codepen https://codepen.io/mxdavis/pen/KxxmKE by inserting font-size: 20px; to between line 24 and 25 (in the a.upper-text class) and you will see the red border no longer ends at the same point like it does when the font is not adjusted. https://codepen.io/mxdavis/pen/dqqzMy
I need the even sized boxes, and the adjusted font size. Flex seems to be the easiest route since upper-text and lower-text cannot be predicted.
Any advice is greatly appreciated.
Thanks!
Update: I realize now if I play with the text sizes and don't make upper and lower texts equal even my first code snippet doesn't work, which is probably why a font increase is throwing it off. Is there a way to accomplish this or should I just set a fixed height and then click to reveal more? https://codepen.io/mxdavis/pen/KxxedE
I was able to accomplish this (for the most part) using flex and grid together.
I still have to guestimate a max template row for unpredictable text but at least I can guarantee the starting points with this.
https://codepen.io/mxdavis/pen/KxxedE
Here's the new css with the .inner now using display: grid instead of flex.
.outer {
display: flex;
flex-flow: row wrap;
.inner {
border: 5px solid yellow;
display: grid;
grid-template-rows: 210px minmax(max-content, 3fr) minmax(max-content, 2fr) 30px;
grid-row-gap: 5px;
text-align: center;
margin-right: 1em;
margin-bottom: 1.5em;
width: 150px;
font-size: 1.00em;
a.image{
border: 5px solid orange;
img {
width: em(160px);
height: em(210px);
}
}
a.upper-text {
border: 5px solid red;
line-height: normal;
}
.lower-text {
border: 5px solid green;
}
.price {
border: 5px solid blue;
margin: 0;
}
}
}
I still would be interested to see how to rely ONLY on the most content for that row, without using tables.

Flex auto margins and previous / next button spacing

I have this situation with Previous/Next Project buttons where I could either have both previous and next project buttons showing, or just one depending on what page the user is on. (First project does not have prev button, last project does not have next button). Same code for all situations.
I used flexbox and justify-content: space-between; to space them normally, and then margin-left: 10px; on the prev button for mobile and it was perfect.
For 1 button case however I added margin-left/right to shove them to the left/right side of page. This overrides margin: auto.
So you see my problem now is with the 2 button situation on mobile. When these buttons collide obviously it looks terrible, I need margin in between but I have margin: auto already on them.
I have added my current state and all 3 situations below:
.project-controls {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.project-controls a {
width: 100%;
max-width: 200px;
padding: 10px 5px;
border: 1px solid #2c2c2c;
font-weight: 600;
text-align: center;
text-decoration: none;
text-transform: uppercase;
color: #2c2c2c;
transition: all 0.3s ease;
}
.project-controls .prev-proj {
margin-right: auto;
}
.project-controls .next-proj {
margin-left: auto;
}
<h1>Two buttons</h1>
<section class="project-controls">
<a class="prev-proj" href="#">Previous Project</a>
<a class="next-proj" href="#">Next Project</a>
</section>
<h1>One button prev</h1>
<section class="project-controls">
<a class="prev-proj" href="#">Previous Project</a>
</section>
<h1>One button next</h1>
<section class="project-controls">
<a class="next-proj" href="#">Next Project</a>
</section>
How can I keep my existing structure and still get that space in between on mobile? My best guess is having some sort of invisible spacer div that I could display with a media query, but just wondering if anyone has a quicker/cleaner solution I'm not thinking of?
Thanks
No need for margin auto on both. You can set a fixed margin-right for the previous element. You also don't need to use justify-content.
.project-controls {
display: flex;
flex-direction: row;
/* no need this too
justify-content: space-between;
*/
}
.project-controls a {
width: 100%;
max-width: 200px;
padding: 10px 5px;
border: 1px solid #2c2c2c;
font-weight: 600;
text-align: center;
text-decoration: none;
text-transform: uppercase;
color: #2c2c2c;
transition: all 0.3s ease;
}
.project-controls .prev-proj {
margin-right: 20px; /* Changed this */
}
.project-controls .next-proj {
margin-left: auto;
}
<h1>Two buttons</h1>
<section class="project-controls">
<a class="prev-proj" href="#">Previous Project</a>
<a class="next-proj" href="#">Next Project</a>
</section>
<h1>One button prev</h1>
<section class="project-controls">
<a class="prev-proj" href="#">Previous Project</a>
</section>
<h1>One button next</h1>
<section class="project-controls">
<a class="next-proj" href="#">Next Project</a>
</section>
I also use previous and next buttons on my web pages.
I also use flexbox and justify-content: space-between or an auto margin, depending on the site (I've switched it up just for variety; ultimately they both have the same effect).
I encountered the same problem as you with having only one button on the first and last pages.
My solution was to add a hidden button on the first and last pages. This keeps the layout behavior consistent on all pages, without a lot of extra CSS (just one or two lines for the .hidden class).
Then on smaller screens, to avoid the "collision" issue altogether, a media query kicks in with flex-direction: column.
.hidden {
visibility: hidden;
width: 0;
}
nav {
display: flex;
justify-content: space-between;
border: 1px dashed blue;
}
#media ( max-width: 500px ) {
nav { flex-direction: column; align-items: center; }
}
<h3>first page</h3>
<nav>
next
</nav>
<h3>middle page</h3>
<nav>
previous
next
</nav>
<h3>last page</h3>
<nav>
previous
</nav>
jsFiddle demo

How to split text in a row with css

Hey guys I'm having a hard time coding row, I can get to split the text, here is my code so far:
.partthree {
display: flex;
flex-wrap: wrap;
margin: 0 90px;
color: aliceblue;
}
.partthree div {
display: inline-block;
flex-grow: 1;
font-family: gotham light;
font-size: 23px;
}
<div class="partthree">
<div class="txt1">
<p>You pick which practice areas you want</p>
</div>
<div class="txt2">
<p>You pick your area by county</p>
</div>
<div class="txt3">
<p>You pick how many leads you want</p>
</div>
</div>
flex-wrap:wrap; might be in the way or to be injected via mediaquerie for small screens if needed.
You can tune children layout also with :
margin and padding
min-width & max-width
.... or else that suits your needs
.partthree {
display: flex;
margin: 0 90px;
color: aliceblue;
}
.partthree div {
display: inline-block;
flex-grow: 1;/* flex:1; would make them equal width */
font-family: gotham light;
font-size: 23px;
/* extra ?*/
margin: 0 0.5em;
border:solid;
text-align:center;
}
body {
background:#555
}
p {
margin:0;
<div class="partthree">
<div class="txt1">
<p>You pick which practice areas you want</p>
</div>
<div class="txt2">
<p>You pick your area by county</p>
</div>
<div class="txt3">
<p>You pick how many leads you want</p>
</div>
</div>