Flex direction property - html

Can somebody please explain why is it important to keep flex direction as column in this case? When you change it to row or row reverse, some portion of the image shrinks in width
JS Fiddle: https://jsfiddle.net/fbshqg0c/7/
.main {
width: 100%;
}
.left {
position: relative;
display: flex;
flex-direction: column;
background-color: #fff;
width: 50%;
}
.text {
display: flex;
align-items: center;
}
.text-img-overlay {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 1.25rem;
}
.width100 {
color: #fff;
text-align: center;
width: 100%;
}
<div class="main">
<div class="left">
<img src="https://via.placeholder.com/350x150">
<div class="text text-img-overlay">
<div class="width100">
<h1>500x320</h1>
</div>
</div>
</div>
</div>

That's because the default value for align-items (alignment of secondary axis: Y when direction is row or X when direction is column) property is stretch, so when you use flex-direction: column the image is stretched on the X axis, but when you change it to flex-direction: row then it's stretched on the Y axis (vertical fit, but not horizontal).
You have to define width: 100% for the image.

I’m not completely sure what you mean because I didn’t see any difference but you don’t have a width value for the image, so probably this will fix your issue.
img {
width: 100%;
}

Related

What is this unwanted and unknown space underneath my div?

Ok so I tried vertically aligning the text in my div. I tried all kinds of stuff. Turns out this little box is something I can't define and it is unknown and unwanted. I know that the green block is padding Anyone got a clue on this? This purple block is bugging me
.menu-intro {
position: relative;
}
.intro-img-div {
position: relative;
height: 300px;
width: 100%;
overflow: hidden;
align-content: center;
margin: auto;
display: flex;
justify-content: center;
align-items: center;
object-fit: contain;
}
.menu-intro-img {
object-fit: contain;
position: relative;
width: 100%;
}
.menu-intro-text {
display: flex;
align-items: center;
flex-direction: column;
flex-flow: column;
height: 300px;
position: absolute;
top: 0;
right: 0;
z-index: 2;
max-width: 50%;
overflow: hidden;
padding: 20px;
text-align: center;
}
.menu-intro-h1 {
margin: 0;
font-size: 3em;
}
.menu-intro-text p {
font-size: 1.5em;
}
<main>
<h1 class="text-centered">Our Menu</h1>
<div class="menu">
<div class="menu-intro">
<div class="intro-img-div">
<img src="style/img/menuintroimg.jpeg" alt="Background image of our food" class="menu-intro-img">
</div>
<div class="menu-intro-text">
<h1 class="menu-intro-h1">A look at <span class="red-text">Jacque's</span></h1>
<p>Scroll down and see what we have to offer!</p>
</div>
</div>
</div>
</main>
TURNS out this space is space that isn't filled out by text but is still registered as part of the div. You need to define another way of justifying content inside the div
justify-content:space-evenly;
Your menu-intro-text is a flex with explicitly defined height: 300px.
The children elements looks to take less part of that height. So the purple area is a part that is left. And Inspector shows it to you in a convenient way. Now using this hint of the Inspector you can decide what to do: add more children to fill that unutilized space or you may want to distribute it with justify-content:space-evenly as it was proposed by #Andelo Motika above or, in my opinion, better with justify-content:space-around

Shrink a row of images to fit container height and maintain aspect ratios

I'd like to know how to shrink a row of images so that they all fit within a div with an unspecified height. The images should never scale up beyond their native height, and they must maintain their aspect ratio. Also, I'd like the height of the containing div to be limited to the native height of the tallest image. The image tags have no height or width attributes.
Here's a fiddle with what I have so far. I approached this using flexbox and object-fit: scale-down. The row of images in question are gray and are in the div with the green background. They currently do not scale at all, but they are at least centered vertically and horizontally how I'd like them to be. Here are before and after images of the effect I'd like to achieve (sorry for switching the green background to yellow in the images). Additional details below the code snippet, but that about sums up the basic question.
body {
font-family: arial;
font-size: 26px;
text-align: center;
color: black;
background-color: white;
}
.smallhint {
font-size: 16px;
color: #8c8c8c;
}
img {
padding: 0;
margin: 0;
font-size: 0;
display: block;
object-fit: scale-down;
min-height: 0;
}
.flex-column {
display: flex;
flex-direction: column;
padding: 0px;
margin: 0px;
height: 90vh;
flex-grow: 0;
min-width: 0;
min-height: 0;
}
.flex-row {
display: flex;
flex-direction: row;
flex: 0 1.5 auto;
justify-content: center;
align-items: center;
background-color: green;
}
.context {
display: flex;
flex-direction: column;
max-height: 100%;
background-color: blue;
}
.primary {
position: relative;
z-index: 0;
right: 0;
bottom: 0;
padding: 0;
font-size: 0;
min-height: 0;
align-items: end;
background-color: orange;
}
.primary img {
margin-left: auto;
margin-right: auto;
border-style: solid;
border-width: 3px;
border-color: black;
height: calc(100% - 2*3px);
}
.mask {
position: absolute;
z-index: 1;
top: 0;
right: 0;
width: 100%;
height: 100%;
font-size: 0;
}
.nonimage {
padding-top: 5px;
display: inline;
background-color: pink;
}
<div class="flex-column">
<div class="primary">
<img src="https://via.placeholder.com/200">
<div class="mask">
<img src="https://via.placeholder.com/200/FF000">
</div>
</div>
<div class="flex-row">
<div class="context">
<img src="https://via.placeholder.com/75x150">
</div>
<div class="context">
<img src="https://via.placeholder.com/150x75">
</div>
</div>
<div class="nonimage">
<div class="smallhint">Some Text<br>Other Text</div>
</div>
</div>
I'm working on a (fixed-height) interface styled with CSS and will likely be asking a series of questions. I'm not great at CSS, so I'm open to approaches that are very different from my failed attempt!
At the top is a single centered image ("primary image"), below that are two other images ("secondary images") in a row, and below that is some text. Eventually, I'd like both sets of images to be responsive to changes in the height and width of the browser. However, I'd like to preferentially scale down the secondary images more than the primary image when the browser is too short to contain everything at native dimensions. For this, it seemed like flexbox containers with various flex-grow values would work here; it seems to work with the primary image somewhat, but the secondary images refuse to scale.
Also, I'm aware that, even if my current approach worked, the object-fit: scale-down strategy would leave behind some unwanted "padding" that will result in visual space between the secondary images. I have a feeling a very different approach may be required to get the effect that I want in the end, since I want the images to sit adjacent to each other without extra space around them. Furthermore, there also seems to be an issue with the container itself when the browser becomes very thin, since a scrollbar appears but it should always be 90vh.
Thank you all for the input!
Add a min-height: 0; rule for .flex-row. I guess that means it was pretty close to working when I asked the question.
This solution retains the issue I mention in my question about the additional "padding" created around images when object-fit: scale-down (or cover) is used. So, that means I'll be asking another question about that topic!

position: fixed prevents elements to be centered properly

I want to center .donut-graphs inside .dashboard horizontally, so the space between the right edge of the sidebar and the left edge of .donut-graphs is the same as the space from the right edge of .donut-graphs and the right edge of the screen. I have managed to do so, but I had to remove position: fixed from .navbar. The problem is, I can't do that because my sidebar has to stay on top of the screen when you scroll up/down, and with position: fixed on .navbar, the graphs aren't centered properly.
HTML:
<div class="container">
<div class="navbar">
</div>
<div class="content">
<div class="dashboard">
<div class="donut-graphs">
<div class="dashboard-income">
Div 1
</div>
<div class="dashboard-overall">
Div 2
</div>
<div class="dashboard-spent">
Div 3
</div>
</div>
</div>
</div>
</div>
CSS:
body {
margin: 0;
}
.container {
display: flex;
align-items: stretch;
max-width: 100%;
min-height: 100vh;
}
.navbar {
background-color: #ddd;
flex: 0 0 230px;
position: fixed;
height: 100vh;
width: 230px;
}
.content {
flex: 1;
overflow-x: auto;
text-align: center;
}
.donut-graphs {
display: inline-flex;
border: 1px solid;
margin: 50px auto 0;
position: relative;
text-align: left;
}
.dashboard-income,
.dashboard-overall,
.dashboard-spent {
height: 256px;
width: 357px;
display: inline-block;
}
.dashboard-income {
background-color: green;
}
.dashboard-overall {
background-color: blue;
}
.dashboard-spent {
background-color: red;
}
How can I overcome the issue?
Demo
position: fixed puts element above everything. That element won't attach to any element in body because it is the way that works. It only becomes dependent of viewport
What you want to achive could be done with position: absolute but parent (whose child you want to center) has to be position: relative for this to work.
Read more about positioning elements in css here
.content { padding-left:230px; }
Should do the trick.
Assigning your navbar a fixed position takes it out of the document flow, so when centering your donut graphs the browser doesn't take the navbar into account.
Giving the .content element a padding equivalent to the width of the navbar makes up for this.
The only problem with this approach is that if .navbar changes dimensions, you'll need to change the padding on .content to match.

How to style a square div dynamically based on the height?

I already read this Q&A and the blog posts that it links to. The problem here is that the referred-to methods only work if you have a set width and are setting the height dynamically. But how can you do it if you need the opposite--the height is known but the width is not?
I have a visual element, specified in CSS, that I need to appear consistently in multiple contexts. (For the purposes of this exercise it may as well be a red square.) The contexts have set heights--e.g. a nav with height x, a list-item with height y, etc. The width of the element, therefore, needs to be based on the height -- not the other way around.
I tried reversing the method mentioned in the linked articles (to use height instead of width, and padding-right instead of padding-top), but it doesn't work -- the element winds up with no width, and thus the red square (.my-box .content) doesn't appear:
HTML:
<div class="outer">
<div class="my-box">
<div class="content">
</div>
</div>
<div class="more-stuff">
Some more stuff goes here
</div>
</div>
CSS:
.outer {
background-color: white;
height: 72px;
padding: 12px;
display: flex;
flex-direction: row;
}
.my-box {
height: 100%;
position: relative;
}
.my-box::before {
content: "";
display: block;
padding-left: 100%;
}
.content {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: red;
}
.more-stuff {
flex: 1 1 auto;
margin-left: 12px;
}
JSFiddle for the above
Does anyone know if this is possible without JS or hardcoding the dimensions every time? Googling finds nothing that works for dynamic height--even with quotation marks. :(
JS is the only reliable option in your case.
In CSS box model (and HTML in general) width and height are not symmetric.
In general HTML has "endless tape" layout model - width is fixed (by view/window) but height is not known upfront - needs to be calculated.
CSS does layout in following steps:
do horizontal layout inside left and right bounds. At the end this will give you content height.
If height:auto (by default) set element height computed at step #1.
Do vertical alignment if needed (table-cell and flexbox elements).
Mathematically speaking height = F(width,content) and F here is a step function - different input width values may give you same output height value. Step function has no determined inverse function - there is no such an inverse function F' that will allow you to calculate width = F'(height,content).
(My pardon for the math on pure CSS subject, but I don't know how to explain it otherwise.)
A little bit a hack, but still a solution.
We create a box with ratio 1:1, set the width and rotate box transform: rotateZ(90deg).
*,
*:before,
*:after {
box-sizing: inherit;
}
html {
box-sizing: border-box;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
body {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
background-color: #F72F4E;
overflow: hidden;
}
.Box {
width: 50vmin; /* or 400px for ex. */
position: relative;
background-color: rgba(0,0,0,.2);
overflow: hidden;
position: relative;
-webkit-transform: rotateZ(90deg);
transform: rotateZ(90deg);
}
.Box:before {
content: "";
display: block;
height: 0;
padding-top: 100%;
}
.Box__content {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 12px;
-webkit-transform: rotateZ(-90deg);
transform: rotateZ(-90deg);
}
<div class="Box">
<div class="Box__content">Box</div>
</div>
P.S.: SVG can be useful in that case, i hope.

Height is not correct in flexbox items in Chrome [duplicate]

This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 6 years ago.
I've got a delicate problem for any CSS guru out there.
My green div has a flexible height, taking up the remaining.
And now I want to put a div inside that div which should be the half of the green div. But it seems like if Chrome treats it like half of the whole page rather than the flex item.
http://jsfiddle.net/unh5rw9t/1/
HTML
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>
CSS
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
}
#half_of_content {
height: 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
#Michael_B explained why Chrome behaves like this:
You gave the body a height: 100%. Then gave its child (.wrapper)
a height: 100%. Then gave its child (.content) a height: 100%.
So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be a 50% height
of body.
However, Firefox disagrees because, in fact, that height: 100% of .content is ignored and its height is calculated according to flex: 1.
That is, Chrome resolves the percentage with respect to the value of parent's height property. Firefox does it with respect to the resolved flexible height of the parent.
The right behavior is the Firefox's one. According to Definite and Indefinite Sizes,
If a percentage is going to be resolved against a flex item’s
main size, and the flex item has a definite flex
basis, and the flex container has a definite main
size, the flex item’s main size must be treated as
definite for the purpose of resolving the percentage, and the
percentage must resolve against the flexed main size of the
flex item (that is, after the layout algorithm below has been
completed for the flex item’s flex container, and the flex
item has acquired its final size).
Here is a workaround for Chrome:
#content {
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
height: auto;
}
This way the available space in #content will be distributed equally among #half_of_content and the ::after pseudo-element.
Assuming #content doesn't have other content, #half_of_content will be 50%. In your example you have a 2 in there, so it will be a bit less that 50%.
html,
body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
You could absolutely position div id="half_of_content".
#content {
flex: 1;
height: 100%;
background-color: green;
position: relative; /* new */
}
#half_of_content {
height: 50%;
background-color: yellow;
position: absolute; /* new */
width: 100%; /* new */
}
DEMO
With regard to your statement:
But it seems like if Chrome treats it like half of the whole page
rather than the flex item.
You gave the body a height: 100%. Then gave its child (.wrapper) a height: 100%. Then gave its child (.content) a height: 100%. So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be 50% height of body.
With absolute positioning, however, you don't need to specify parent heights.
Nesting flexboxes is a little buggy. I reworked your markup a little by adding an inner wrapper with display: flex; which seems to do the job. Here is the fiddle (also using class names instead of ids).
<div class="content">
<div class="wrapper-inner">
2
<div class="half">
2.1
</div>
</div>
</div>
.wrapper-inner {
position: absolute;
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
Fix:
on #content set
display: flex;
flex-flow: column nowrap;
justify-content: flex-end
on #half_of_content set flex: 0 0 50%;
Caveat: you need to add an extra div as a child of #content.
Here's the full example:
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
display:flex;
flex-flow: column nowrap;
justify-content: flex-end;
background-color: green;
}
#half_of_content {
flex: 0 0 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>