button not aligned with image in div - css

In the following image , the button (Questions) is lower than the image (white rectangle). They both are inside the same div. Why? The page has a top level css-grid with 3 rows.
.grid-container {
display: grid;
grid-template-rows: [nav-row-start]auto [nav-row-end logo-nav-row-start] auto [logo-nav-row-end content-row-start] auto [content-row-end];
}
.nav-style {
height: 5vh;
/*make nav div take 5% of space of viewport*/
background-color: black;
}
.logo-nav-style {
height: 20vh;
/*make logo-nav div take 20% of space of viewport*/
background-color: gray;
}
.nav-flexbox-container {
display: flex;
flex-direction: row-reverse;
}
.content-style {
height: 75vh;
/*make content div take 75% of space of viewport*/
background-color: white;
}
#nav {
grid-row: nav-row-start/nav-row-end;
margin: 0px;
}
#logo-nav {
grid-row: logo-nav-row-start/logo-nav-row-end;
margin: 0px;
}
#content {
grid-row: body-row-start/body-row-end;
margin: 0px;
}
#profile-pic {
margin: 5px;
}
#mail-icon-pic {
margin: 5px;
}
#stats-icon-pic {
margin: 5px;
}
#logo-image {
/*the max width and max height rule will make the image fit inside the div. If the image is bigger than div, the image will
contract, if the image is smaller than the div, the image will expand*/
max-width: 100%;
max-height: 100%;
}
body {
margin: 0px;
}
<div class="grid-container">
<div id="nav" class="nav-style nav-flexbox-container">
<img id="stats-icon-pic" src="stats_icon.png">
<img id="mail-icon-pic" src="mail_icon.png">
</div>
<div id="logo-nav" class="logo-nav-style">
<img id="logo-image" src="example_logo.png"/>
<button type="button">Questions</button>
<!-- this button is lower than the image-->
</div>
<div id="content" class="content-style">body</div>
</div>

I can't answer the "why" part, but one solution is to add display: flex and align-items: flex-end to .logo-nav-style.
Also, I wouldn't lock .content-style to height: 75vh but use min-height: 75vh instead so the content can expand beyond that.
I'm also confused why you got flex-direction: row-reverse; on your .nav-flexbox-container. Why not just put the elements in the correct order to begin with?
.grid-container {
display: grid;
grid-template-rows: [nav-row-start]auto [nav-row-end logo-nav-row-start] auto [logo-nav-row-end content-row-start] auto [content-row-end];
}
.nav-style {
height: 5vh;
/*make nav div take 5% of space of viewport*/
background-color: black;
}
.logo-nav-style {
height: 20vh;
/*make logo-nav div take 20% of space of viewport*/
background-color: gray;
/* Rickard's addition */
display: flex;
align-items: flex-end;
}
.nav-flexbox-container {
display: flex;
flex-direction: row-reverse;
}
.content-style {
min-height: 75vh;
/*make content div take 75% of space of viewport*/
background-color: white;
}
#nav {
grid-row: nav-row-start/nav-row-end;
margin: 0px;
}
#logo-nav {
grid-row: logo-nav-row-start/logo-nav-row-end;
margin: 0px;
}
#content {
grid-row: body-row-start/body-row-end;
margin: 0px;
}
#profile-pic {
margin: 5px;
}
#mail-icon-pic {
margin: 5px;
}
#stats-icon-pic {
margin: 5px;
}
#logo-image {
/*the max width and max height rule will make the image fit inside the div. If the image is bigger than div, the image will
contract, if the image is smaller than the div, the image will expand*/
max-width: 100%;
max-height: 100%;
}
body {
margin: 0px;
}
<div class="grid-container">
<div id="nav" class="nav-style nav-flexbox-container">
<img id="stats-icon-pic" src="stats_icon.png">
<img id="mail-icon-pic" src="mail_icon.png">
</div>
<div id="logo-nav" class="logo-nav-style">
<img id="logo-image" src="example_logo.png"/>
<button type="button">Questions</button>
<!-- this button is lower than the image-->
</div>
<div id="content" class="content-style">body</div>
</div>

Related

Div With Negative Margin and Background Color Not Showing In Flexbox From Outside

I would like to have a div with negative margin impinge upon a flexbox from outside and below the flexbox including its background color. In the attached snippet, the title "Up Up and ..." has a white background that is not showing. The position of the title itself is fine. If you comment out flex-row, you'll see it appear in the lower div. Is this possible to do with flex-box?
I've checked other flex-box negative margin posts. They deal with margins within the flexbox. I wouldn't be doing this if it wasn't a hard requirement of converting a fixed page layout into a responsive one. In addition, the real world project uses an image in the left child.
.parent {
background-color: cyan;
}
.left-child {
height: 16em;
background-color: aquamarine;
}
.right-child {
height: 16em;
background-color: orange;
}
.negative {
margin-top: -4em;
margin-left: 3em;
background-color: white;
}
.flex-row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.mf6 {flex: 0 0 50%;}
<div class="flex-row parent">
<div class = "mf6 left-child">
<h1>Left Header Content</h1>
</div>
<div class = "mf6 right-child">
<h1>Right Header Content</h1>
</div>
</div>
<div class="negative">
<h1>Up Up and Away, this is really long in order to make it into the second section. It should have a white background</h1>
</div>
you need to add position:relative; to .negative
here it is:
.parent {
background-color: cyan;
}
.left-child {
height: 16em;
background-color: aquamarine;
}
.right-child {
height: 16em;
background-color: orange;
}
.negative {
margin-top: -4em;
margin-left: 3em;
position:relative; // this line
background-color: white;
}
.flex-row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.mf6 {flex: 0 0 50%;}

How to fit 2 elements to page height?

I'm developing an app with the interface that is supposed to fit the page (only some internal elements may have scrolling). The basic layout consists of a header and the main section:
<div class="page">
<Navigation/> <!-- a Vue component -->
<main class="page__main">
...
</main>
</div>
currently, CSS has hardcoded height of the header (Navigation):
.page {
height: 100vh;
}
.page__main {
height: calc(100vh - 80px); /* 80px is the height of the header */
}
I'd like to get rid of this hardcoded bit but make sure .page__main's height gets no larger than 100vh - height of Navigation. Is there a way to do this without JS? I suspect that there are some options that can be used with
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
but just using that with
.page__main {
flex-shrink: 1;
}
doesn't work: .page__main has children which use height in percents and once I set flex-shrink: 1; instead of height: calc(100vh - 80px); those grow and the interface is broken.
To illustrate the problem better, here's the current state:
body { padding: 0; margin: 0; }
.page {
height: 100vh;
background: blue;
}
.page__navigation {
height: 80px;
background: gray;
}
.page__main {
height: calc(100vh - 80px);
}
.part1 {
height: 50%;
background: #eeeeee;
overflow-y: scroll;
}
.part2 {
height: 50%;
background: #cccccc;
}
<div class="page">
<div class="page__navigation">nav stuff</div>
<main class="page__main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</main>
</div>
and here's what happen when I try to "set height" via flex:
body { padding: 0; margin: 0; }
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: blue;
}
.page__navigation {
height: 80px;
background: gray;
}
.page__main {
flex-shrink: 1;
}
.part1 {
height: 50%;
background: #eeeeee;
overflow-y: scroll;
}
.part2 {
height: 50%;
background: #cccccc;
}
<div class="page">
<div class="page__navigation">nav stuff</div>
<main class="page__main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</main>
</div>
You can consider a nested flexbox container and don't forget the use of min-height:0; to allow the elements to shrink.
body { padding: 0; margin: 0; }
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: blue;
}
.page__navigation {
height: 80px;
background: gray;
}
.page__main {
flex-grow: 1; /* Fill the remaining space*/
display:flex; /* Nested Container*/
flex-direction:column;
min-height:0; /* Allow the element to shrink */
}
.part1 {
flex-basis: 50%;
background: #eeeeee;
overflow-y: scroll; /* Allow the element to shrink */
}
.part2 {
flex-basis: 50%;
min-height:0; /* Allow the element to shrink */
background: #cccccc;
}
<div class="page">
<div class="page__navigation">nav stuff</div>
<main class="page__main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</main>
</div>
Use flex-grow. Keep everything as the second one (flex one) and change:
Edit
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: blue;
}
.page__main {
height: 100%;
min-height: 0;
flex: 1 1 auto;
}
Three value flex means flex: flex-grow | flex-shrink | flex-basis.
Flex-grow tells our element whether or not it can take up additional space.
Flex-shrink works very similarly to flex-grow, only instead of dealing with extra space, it deals with space not needed by an elements content.
Flex basis is best used when in conjunction with either flex-shrink or flex-grow.
You can check this article to understand better.
I would suggest css-grid approach : -
.page {
background: gray;
display: grid;
grid-template-rows: 100px auto;
height: 100vh;
color: white;
}
.nav {
grid-row: 1/2;
background: brown;
}
.main {
grid-row: 2/3;
background: green;
display: grid;
grid-template-rows: 30% 70%;
}
.part1 {
overflow: auto
}
.part2 {
background: blue
}
<div class="page">
<div class="nav">Nav</div>
<div class="main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</div>
</div>
</div>

CSS: flex-grow maintain vertical aspect ratio

I am creating a website with a circular menu. The website content should fit all onto the homepage without the need to scroll. The menu needs to fill the remaining space on the homepage. However, I am unsure how to maintain the shape of the circle while filling the remaining space on the homepage using flex-grow: 1. Is there a way I can do this with pure CSS? Setting the menu to a set viewport size is not acceptable, it needs to fill the remaining space. I am not having luck using the traditional padding-top: 100% to maintain aspect ratio. The circle is not quite circular and it takes up twice the remaining space.
body {
height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
}
#title {
font-size: 30px;
}
#circle {
background: black;
border-radius: 50%;
flex-grow: 1;
padding-top: 100%;
}
#footer {
background: black;
color: white;
}
<body>
<div id="title">Title</div>
<div>navigation</div>
<div id="circle"></div>
<div id="footer">Footer</div>
</body>
Edit
I have figured out a way to maintain the aspect ratio of the circle filling the remaining space with flex grow. However, it is what I would consider a hack so I am leaving this question open.
body {
height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
}
#title {
font-size: 30px;
}
#circle {
background: black;
border-radius: 50%;
flex-grow: 1;
/*width: max-content;*/
padding: 0%;
align-self: center;
}
#circle img {
height: 100%;
width: auto;
justify-content: center;
}
#footer {
background: black;
color: white;
}
<body>
<div id="title">Title</div>
<div>navigation</div>
<div id="circle"><img src="https://luxury.zappos.com/search/imgs/blank.20190219170746.png"></div>
<div id="footer">Footer</div>
</body>
Edit 2
It seems I was mislead by caniuse.com. This solution does not seem to work in most browsers besides chrome. Is there another solution?
Put the circle div inside a wrapper div in your HTML:
<div id="circle-wrap">
<div id="circle"></div>
</div>
Then move the flex rule to the wrapper:
#circle-wrap {
flex-grow: 1;
}
body {
height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
}
#title {
font-size: 30px;
}
#circle-wrap {
flex-grow: 1;
}
#circle {
background: black;
border-radius: 50%;
padding-top: 100%;
}
#footer {
background: black;
color: white;
}
<body>
<div id="title">Title</div>
<div>navigation</div>
<div id="circle-wrap">
<div id="circle"></div>
</div>
<div id="footer">Footer</div>
</body>

Center text in 100%-screen-width div in small wrapper

I want to center a div and it's text, in a 100%-screen-width div, which is in a smaller wrapper.
.wrapper {
height: 800px;
width: 900px;
margin: auto;
background-color: #000000;
}
.box-wrapper {
width: 1000%;
position: relative;
left: -500%;
background-color: #FF6600;
}
.box {
background-color: #FF0000;
width: 600px;
position: relative;
left: 50%;
color: #00FF00;
}
span {
text-align: center;
display: block;
}
<div class="wrapper">
Random text for wrapper-div
<div class="box-wrapper">
<div class="box">
<span>ABC</span>
<span>DEF</span>
<span>GHI</span>
</div>
</div>
</div>
This code is kind of working but not perfect.
The red div should be moved a bit to the right, also the way
of doing it is not the best in my opinion.
I want a more robust and responsive solution.
To be more clear, it's for the pink division on the bottom
of this website: http://ndvibes.com
There the code is working 99% of the times and reponsive. But on some computers/screens it's 50% off. So I want a less-hacky (without transform etc) and more standard, robust way of getting that effect.
Wrapper 900px > 100%-screen-width coloured div > Centered text in that coloured div.
How can I achieve this the best as possible?
Thanks!
How about this approach, using absolute positioned pseudo elements. The outer-space div with overflow:hidden is to prevent a horizontal scroll bar appearing. I have added padding-top to the .wrapper just so you can see the snippet running in full screen mode.
body {
margin:0;
}
.outer-space {
overflow: hidden;
padding-top:80px;
}
.wrapper {
height: 800px;
width: 100%;
max-width: 900px;
margin: auto;
background-color: #000000;
}
.box {
background-color: #8904B1;
margin:0 auto;
color: #ffffff;
position: relative;
z-index: 2;
padding:10px 0;
}
.box-wrapper {
position: relative;
width:100%;
max-width: 600px;
margin:0 auto;
}
.box-wrapper:before, .box-wrapper:after {
content:"";
position: absolute;
height:100%;
width:100vw;
background-color: #8904B1;
top: 0;
z-index: 1;
}
.box-wrapper:before {
left:-100%;
}
.box-wrapper:after {
right:-100%;
}
span {
text-align: center;
display: block;
}
<div class="outer-space">
<div class="wrapper">
Random text for wrapper-div
<div class="box-wrapper">
<div class="box">
<span>Crazy full width window</span>
<span>absolute positioned pseudo elements</span>
<span>with centered content div and centered text thingy</span>
<span>all inside of a fixed width page wrapper!</span>
<br><span>““”̿ ̿ ̿ ̿ ̿’̿’̵͇̿̿з=(•̪●)=ε/̵͇̿̿/̿ ̿ ̿ ̿ ̿’““</span>
</div>
</div>
</div>
</div>
To center child element, add the following to the parent wrap will center all child.
display: flex;
align-items: center;
justify-content: center;
If you want 100% screen width, use viewport (100vw) for 100% screen width
viewport
The #viewport CSS at-rule contains a set of nested descriptors in a CSS block that is delimited by curly braces. These descriptors control viewport settings, primarily on mobile devices.
1vw = 1% of viewport width
1vh = 1% of viewport height
1vmin = 1vw or 1vh, whichever is smaller
1vmax = 1vw or 1vh, whichever is larger
REF: #viewport
REF: Viewport Sized Typography
body {
margin: 0;
}
.wrapper {
height: 800px;
width: 900px;
margin: auto;
background-color: #000000;
}
.box-wrapper {
width: 900px;
max-width: 900px;
position: relative;
background-color: #FF6600;
display: flex;
align-items: center;
justify-content: center;
}
.outer-wrapper {
width: 100vw;
display: flex;
align-items: center;
justify-content: center;
}
.box {
width: 80%;
background-color: #FF0000;
position: relative;
color: #00FF00;
}
span {
text-align: center;
display: block;
}
<div class="outer-wrapper">
<div class="wrapper">
<p>Random text for wrapper-div</p>
<div class="box-wrapper">
<div class="box">
<span>ABC</span>
<span>DEF</span>
<span>GHI</span>
</div>
</div>
</div>
</div>

Why isn't `height: 100%` and absolute positioning working in flexbox?

I'm trying to make a child div of a flexbox layout fill its parent. In any other context setting the width/height to 100% causes a div to fill its parent... I only wish to use flexbox for my top level layout.
Problems
#map-container div will not fill #col1 even though it has height 100% set.
#controls div appears outside #col1 completely. I've previously used absolute layout to align boxes to corners without problems. Being inside a flexbox grand-parent seems to cause issues.
What I'm expecting is #map-container and #map to fill #col1 and #controls to align to bottom right-hand corner of #map.
.wrapper, html, body {
height:100%;
margin:0;
}
#col1 {
display: flex;
}
#map-container {
background-color: yellow;
width: 100%;
height: 100%;
}
#map {
background-color: purple;
width: 100%;
height: 100%;
}
#controls {
background-color: orange;
position: absolute;
right: 3px;
bottom: 3px;
width: 100px;
height: 20px;
}
.wrapper {
display: flex;
flex-direction: column;
}
#row1 {
background-color: red;
}
#row2 {
flex:2;
display: flex;
}
#col1 {
background-color: green;
flex: 1 1;
}
#col2 {
background-color: blue;
flex :0 0 240px;
}
<div class="wrapper">
<div id="row1">Header</div>
<div id="row2">
<div id="col1">
<div id="map-container">
<div id="map">
Map
</div>
<div id="controls">Controls</div>
</div>
</div>
<div id="col2">Sidebar</div>
</div>
</div>
#map-container div will not fill #col1 even though it has height 100% set.
It won't work that way, because for a percentage unit to work, it needs to have height set on its parent all the way up. This fights against the flex model, where the flex-items are distributed and arranged by the flex-box layout and have no dimensions set. Why use a flex layout when all your elements are 100%? Either do a 100% on all your element all the way up, or do a flex on all containers.
If you stick to flex layout, then you will have to get into nested flex. Otherwise, you will get #map-container to fill-up, but not the #map.
This fiddle http://jsfiddle.net/abhitalks/sztcb0me illustrates that problem.
#controls div appears outside #col1 completely. I've previously used absolute layout to align boxes to corners without problems. Being
inside a flex-box grand-parent seems to cause issues.
The only issue is that you are positioning it absolutely, but in relation to what? You need to position your #map-container relatively for that to work.
Here is how:
Fiddle: http://jsfiddle.net/abhitalks/sztcb0me/1/
Snippet:
* { box-sizing: border-box; padding: 0; margin: 0; }
html, body, .wrapper { height:100%; width: 100%; }
.wrapper { display: flex; flex-direction: column; }
#row1 { flex: 0 1 auto; background-color: red; }
#row2 { flex: 2 0 auto; display: flex; }
#col1 { flex: 1 0 auto; display: flex; background-color: green; }
#col2 { flex: 0 0 240px; background-color: blue; }
#map-container {
flex: 1 0 auto; display: flex;
position: relative; background-color: yellow;
}
#map { flex: 1 0 auto; background-color: purple; }
#controls {
background-color: orange;
position: absolute;
right: 3px; bottom: 3px;
width: 100px; height: 20px;
}
<div class="wrapper">
<div id="row1">Header</div>
<div id="row2">
<div id="col1">
<div id="map-container">
<div id="map">
Map
</div>
<div id="controls">Controls</div>
</div>
</div>
<div id="col2">Sidebar</div>
</div>
</div>
the problem is that it's wrapped in #map-container
.wrapper, html, body {
height:100%;
margin:0;
}
#col1 {
display: flex;
}
#map-container {
background-color: yellow;
width: 100%;
height: 100%;
}
#map {
background-color: purple;
width: 100%;
/* height: 100%; */
display: flex;
flex-wrap: wrap-reverse;
justify-content: space-between;
}
#controls {
background-color: orange;
position: relative;
/*right: 3px;
bottom: 3px;*/
width: 100px;
height: 20px;
}
.wrapper {
display: flex;
flex-direction: column;
}
#row1 {
background-color: red;
}
#row2 {
flex:2;
display: flex;
}
#col1 {
background-color: green;
flex: 1 1;
}
#col2 {
background-color: blue;
flex :0 0 240px;
}
<div class="wrapper">
<div id="row1">Header</div>
<div id="row2">
<div id="col1">
<!-- <div id="map-container"> -->
<div id="map">
Map
<div id="controls">Controls</div> <!-- add it here -->
</div>
<!-- <div id="controls">Controls</div> -->
<!--</div> -->
</div>
<div id="col2">Sidebar</div>
</div>
</div>
adding an absolute position controls in that way is not optimal (in the snippet I commented it out) ; you can place the controlsnested in #map (and use flex properties for correcting placement)

Resources