canvas having odd behaviour with width and height - html

So I'm having some issues using <canvas>. It's taking up too much room when at 100% height and width and when it's set at only 100% height, it still causes and overflow for some reason.
Examples
With width and height at 100%, canvas takes up way too much room
.flex {
display: flex;
flex-direction: column;
height: 100vh;
}
.upper {
background-color: blue;
height: 10%;
}
.lower {
flex: 1;
background-color: orange;
}
html, body {
padding: 0;
margin: 0;
}
canvas {
height: 100%;
width: 100%;
background-color: red;
padding: 0;
margin: 0;
}
.inner {
width: 100%;
height: 100%;
background-color: yellow;
position: relative;
}
<div class="flex">
<div class="upper">
</div>
<div class="lower">
<div class='inner'>
<canvas></canvas>
</div>
</div>
</div>
Here, canvas is set at 100% height, yet it causes an overflow for some reason.
.flex {
display: flex;
flex-direction: column;
height: 100vh;
}
.upper {
background-color: blue;
height: 10%;
}
.lower {
flex: 1;
background-color: orange;
}
html, body {
padding: 0;
margin: 0;
}
canvas {
height: 100%;
background-color: red;
padding: 0;
margin: 0;
}
.inner {
width: 100%;
height: 100%;
background-color: yellow;
}
<div class="flex">
<div class="upper">
</div>
<div class="lower">
<div class='inner'>
<canvas></canvas>
</div>
</div>
</div>

Related

Make content scroll horizontally within nested flex containers with position sticky

I have the following layout (see snippet below).
This is the expected behavior.
The problem is:
Once the extra-large-content is simulated (by removing the comment on the extra-large-content CSS rule), it breaks the layout.
I would like the extra-large-content to scroll horizontally while staying inside column-3.
Is this even possible?
(the code is also available here https://codepen.io/Ploddy/pen/NWXOgMG?editors=1100)
body {
height: 1920px;
margin: 0;
}
.container {
display: flex;
border: 1px solid #ccc;
margin: 1rem;
}
.container > * {
border: 1px solid #ccc;
position: sticky;
top: 0;
align-self: flex-start;
flex-grow: 1;
margin: 1rem;
}
#column-3 {
height: 300px;
}
#extra-large-content {
background-color: lightgreen;
/*width: 3000px;*/
}
<div class="container">
<div>
column-1
</div>
<div class="container">
<div>
column-2
</div>
<div id="column-3">
column-3
<div id="extra-large-content">
extra-large content
</div>
</div>
</div>
</div>
This should work nicely for you. Essentially, I just specified width's on the .container elements. In theory, you could put overflow-x: scroll; on the .container, however, this would break your sticky positioning.
Edit ~ OP wants the extra-large content to scroll horizontally, not the entire column-3.
Set overflow-x: scroll; on the new parent wrapper of the div that has the 3000px static width.
body {
height: 1920px;
margin: 0;
}
.container:first-child {
max-width: 100%;
}
.container:first-child > div:first-child {
width: 40%;
}
.container:nth-child(2) {
width: 60%;
}
.container:nth-child(2) > div:first-child {
margin: 1em 0em 1em 1em;
}
.container {
display: flex;
border: 1px solid #ccc;
margin: 1rem;
}
.container>* {
border: 1px solid #ccc;
position: sticky;
top: 0;
align-self: flex-start;
flex-grow: 1;
margin: 1rem;
}
.wrapper {
display: flex;
flex-direction: column;
width: 40%;
}
#column-3 {
background-color: salmon;
}
#extra-large-content {
height: 300px;
width: 3000px;
background-color: lightgreen;
}
.xl-content-wrapper {
overflow-x: scroll;
}
<div class="container">
<div>column-1</div>
<div class="container">
<div>column-2</div>
<div class="wrapper">
<div id="column-3">column-3</div>
<div class="xl-content-wrapper">
<div id="extra-large-content">extra-large content</div>
</div>
</div>
</div>
</div>
The issue comes from using flexbox.
Switching to grid fixes the problem.
body {
height: 1920px;
margin: 0;
}
#primary-container {
position: relative;
display: flex;
margin: 1rem;
}
#secondary-container {
position: relative;
display: grid;
grid-template-columns: max-content 1fr;
align-items: start;
}
#column-3 {
display: grid;
grid-auto-rows: min-content;
height: 200px;
}
#content-wrapper {
overflow: auto;
}
#extra-large-content {
width: 3000px;
background-color: lightgreen;
}
.sticky {
position: sticky;
top: 0;
align-self: flex-start;
}
.border {
border: 1px solid #ccc;
}
<div id="primary-container" class="border">
<div class="sticky">
column1
</div>
<div id="secondary-container" class="border">
<div class="sticky">
column2
</div>
<div id="column-3" class="sticky border">
column3
<div id="content-wrapper">
<div id="extra-large-content">
extra-large content
</div>
</div>
...
</div>
</div>
</div>

Content height is not automatically adjusted when scrolling

I am trying to create a modal that has a footer and an header. The content has two columns: LeftSection and RightSection. I want to have the second column fill the height of the content depending on what the first columns height is (which can differ based on content). From the snippet, this means to have the black div go down as much as the red one does.
.Container {
margin: auto auto;
width: 80vw;
height: 250px;
background-color: #8080801a;
flex: 1;
display: flex;
flex-direction: column;
}
.Header {
height: 50px;
width: 100%;
background-color: #61dafb;
}
.FlexContainer {
flex: 1;
display: flex;
overflow: auto;
}
.LeftSection {
width: 200px;
height: 400px;
background: red;
}
.RightSection {
width: 100%;
background-color: black;
}
.Footer {
height: 50px;
background-color: blue;
width: 100%;
}
<div class="Container">
<div class="Header"></div>
<div class="FlexContainer">
<div class="LeftSection" ></div>
<div class='RightSection' ></div>
</div>
<div class='Footer' />
</div>
Do you want this?
.Container {
margin: auto auto;
width: 80vw;
height: 250px;
background-color: #8080801a;
flex: 1;
display: flex;
flex-direction: column;
}
.Header {
height: 50px;
width: 100%;
background-color: #61dafb;
}
.FlexContainer {
flex: 1;
display: flex;
overflow: auto;
}
.LeftSection {
width: 200px;
height: 400px;
background: red;
position: sticky;
top: 0;
}
.RightSection {
width: 100%;
background-color: black;
position: sticky;
top: 0;
}
.Footer {
height: 50px;
background-color: blue;
width: 100%;
}
<div class="Container">
<div class="Header"></div>
<div class="FlexContainer">
<div class="LeftSection" ></div>
<div class='RightSection' ></div>
</div>
<div class='Footer' />
</div>

Image not taking parent height

I have following html:
<div class='fullHeight'>
<div class='flexbox'>
<div class='first'>
<p>foo</p>
</div>
<div class='second'>
<p>bar</p>
<img src='http://www.mandysam.com/img/random.jpg'>
</div>
</div>
</div>
and css:
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fullHeight {
height: 100vh;
background-color: red;
}
.flexbox {
display: flex;
flex-direction: column;
height: 100%;
maxHeight: 100%;
width: 100%;
background-color: green;
}
.first {
background-color: magenta;
}
.second {
background-color: yellow;
flex: 1 1 auto;
max-height: 100%;
height: 100%;
widht: auto;
}
As long there is no image, everything works fine:
But as soon as a picture comes in, it overflows the container, instead of being shrinked to fit available height:
Codepen
You missed
display: flex;
flex-direction: column;
in your .second class, that's why the flex property isn't doing anything. Also it should be max-height instead of maxHeight and width instead of widht.
You can use background-image for your purpose.
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fullHeight {
height: 100vh;
background-color: red;
}
.flexbox {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
background-color: green;
}
.first {
background-color: magenta;
}
.second {
background-color: yellow;
display: flex;
flex-grow: 1;
flex-direction: column;
}
.container {
background-color: green;
flex-grow: 1;
background-image: url('http://www.mandysam.com/img/random.jpg');
background-size: contain;
background-repeat: no-repeat;
}
<div class='fullHeight'>
<div class='flexbox'>
<div class='first'>
<p>foo</p>
</div>
<div class='second'>
<p>bar</p>
<div class="container">
</div>
</div>
</div>
</div>
Add height and width properties to your image. Or just height. Maybe also object-fit: cover;
.second img {
height: 100%;
width: 100%;
object-fit: cover;
}
Using positions is the other solution but it's very risky and it depends on your plan for future code in this project!!
.second {
background-color: yellow;
flex: 1 1 auto;
max-height: 100%;
height: 100%;
widht: auto;
position:relative
}
.second img{
height: 95%;
width: 100%;
position:absolute;
bottom:0;
right:0;
}

Why overflow-y may affect horizontal layout in flex?

Consider the following flex layout:
body {
margin: 0;
}
.container {
background: red;
color: white;
height: 100vh;
display: flex;
}
.left {
flex-grow: 1;
height: 100%;
padding: 1em;
}
.main-content {
background: blue;
height: 130%;
}
.right {
height: 100%;
}
.side-content-upper {
padding: 1em;
height: 50%;
}
.side-content-lower {
padding: 1em;
height: 60%;
background: black;
}
<div class="container">
<div class="left">
<div class="main-content">some some some some some some some some some some some some some some some some some some some some some</div>
</div>
<div class="right">
<div class="side-content-upper">more</div>
<div class="side-content-lower">more</div>
</div>
</div>
Since heights of .main-content and of .side-content-upper plus that of .side-content-lower are greater than 100%, we get vertical overflow. Now let's make the first column fit the screen height and scroll separately by adding box-sizing: border-box; overflow-y: scroll; (to make this more compact, I align unchanged CSS into single lines):
body { margin: 0; }
.container { background: red; color: white; height: 100vh; display: flex; }
.left {
flex-grow: 1;
height: 100%;
padding: 1em;
box-sizing: border-box;
overflow-y: scroll;
}
.main-content { background: blue; height: 130%; }
.right {
height: 100%;
}
.side-content-upper { padding: 1em; height: 50%; }
.side-content-lower { padding: 1em; height: 60%; background: black; }
<div class="container">
<div class="left">
<div class="main-content">some some some some some some some some some some some some some some some some some some some some some</div>
</div>
<div class="right">
<div class="side-content-upper">more</div>
<div class="side-content-lower">more</div>
</div>
</div>
Works fine, doesn't it? Let's now apply the same style to the .right container:
body { margin: 0; }
.container { background: red; color: white; height: 100vh; display: flex; }
.left {
flex-grow: 1;
height: 100%;
padding: 1em;
box-sizing: border-box;
overflow-y: scroll;
}
.main-content { background: blue; height: 130%; }
.right {
height: 100%;
box-sizing: border-box;
overflow-y: scroll;
}
.side-content-upper { padding: 1em; height: 50%; }
.side-content-lower { padding: 1em; height: 60%; background: black; }
<div class="container">
<div class="left">
<div class="main-content">some some some some some some some some some some some some some some some some some some some some some</div>
</div>
<div class="right">
<div class="side-content-upper">more</div>
<div class="side-content-lower">more</div>
</div>
</div>
If your screen resolution is not too high, you'll see what I'm not expecting: the right column not only fits height and gets vertical scroll, but also shrinks and gets horizontal scroll. Why is that? It doesn't seem just the width of the vertical scrollbar: switch overflow-y of .right from scroll to hidden and you again will get .right deformed. I'm puzzled how to reason about this. Just in case, here's what I see with hidden:
Here are two 'fixes' for what it's worth - I know you're looking for an explanation more than a solution but hopefully this will help explain by example. I'm not confident I can detail the intricacies of what is happening here but it is basically do with the way scroll bars interact with with the box model, and how flex handles dimensions. If anyone more knowledgeable can shed some light please chime in.
Give the right div it's own flex property:
body { margin: 0; }
.container { background: red; color: white; height: 100vh; display: flex; }
.left {
flex: 5;
height: 100%;
padding: 1em;
box-sizing: border-box;
overflow-y: scroll;
}
.main-content { background: blue; height: 130%; }
.right {
flex: 1;
height: 100%;
box-sizing: border-box;
overflow-y: scroll;
}
.side-content-upper { padding: 1em; height: 50%; }
.side-content-lower { padding: 1em; height: 60%; background: black; }
<div class="container">
<div class="left">
<div class="main-content">some some some some some some some some some some some some some some some some some some some some some</div>
</div>
<div class="right">
<div class="side-content-upper">more</div>
<div class="side-content-lower">more</div>
</div>
</div>
Give the .side-content-upper and .side-content-lower a box-sizing: border-box property.
body { margin: 0; }
.container {
background: red;
color: white;
height: 100vh;
display: flex;
}
.left {
flex: 1;
height: 100%;
padding: 1em;
box-sizing: border-box;
overflow-y: scroll;
}
.main-content { background: blue; height: 130%; }
.right {
height: 100%;
box-sizing: border-box;
overflow-y: scroll;
}
.side-content-upper { padding: 1em; box-sizing: border-box; height: 50%; width: 100%; }
.side-content-lower { padding: 1em; box-sizing: border-box; height: 60%; background: black; width: 100%;}
<div class="container">
<div class="left">
<div class="main-content">some some some some some some some some some some some some some some some some some some some some some</div>
</div>
<div class="right">
<div class="side-content-upper">more</div>
<div class="side-content-lower">more</div>
</div>
</div>
One final note: when you give overflow to both the left and right divs, the container loses its implicit overflow: auto which was spacing your elements for you. This was causing the shrink issue - if you add overflow-y: scroll back on the container in your last demo the elements will regain their original proportions.
can use java script to help you by available screen height
add jquery.js in first
<script type="text/javascript">
$(document).ready(function(){
var y = screen.availHeight;
$(".container").css('height',y +'px');
$(".left").css('height',y +'px');
$(".right").css('height',y +'px');
$(".main-content").css('height',(y * 1.3) +'px');
$(".side-content-upper").css('height',(y * .5)
+'px');
$(".side-content-lower").css('height',(y * .6)
+'px');
});
</script>
<style type="text/css">
body { margin: 0; }
.container{
background: red;
color: white;
display: flex;
flex-wrap:wrap;
}
.left {
flex-grow: 1;
padding: 1em;
box-sizing: border-box;
overflow-y:scroll;
}
.main-content{ background: blue;}
.right{box-sizing: border-box;overflow-y: scroll;}
.side-content-upper { padding: 1em; }
.side-content-lower { padding: 1em; background:
black; }
</style>

2nd Column fill remaining screen height not working

I have a navbar with a fixed height, underneath a control div with also a fixed height and below that I have another div calendar. calendar is scrollable. I want the calendar height to have the remaining screen height below control and the bottom of the screen. This way the window is not scrollable, only the calendar is scrollable. However setting height: 100% does not work and flex: 1 neither.
This is what I have when I set the height of calendar to a fixed height but as I explained I want the height to be the rest of the screen size.
Any Idea?
.navbar {
height: 50px;
background-color: indianred;
}
.window {
display: flex;
flex-direction: column;
flex: 1;
}
.control {
height: 100px;
background: khaki;
}
.calendar {
height: 200px;
width: 100%;
bottom: 0;
left: 0;
}
.wrapper {
position: relative;
background-color: lightgray;
width: 100%;
height: 100%;
overflow: scroll;
}
.main {
width: 1500px;
height: 1500px;
background-color: rosybrown;
display: flex;
flex-direction: column;
}
<nav class="navbar"></nav>
<div class="window">
<div class="control">
</div>
<div class="calendar">
<div class="wrapper">
<div class="main">
</div>
</div>
</div>
</div>
Run this Code below:
I used height: calc() method full height of the screen minus 150px for nav and controls.
.navbar {
height: 50px;
background-color: indianred;
}
.window {
display: flex;
flex-direction: column;
flex: 1;
}
.control {
height: 100px;
background: khaki;
}
.calendar {
height: calc(100vh - 150px);
width: 100%;
bottom: 0;
left: 0;
}
.wrapper {
position: relative;
background-color: lightgray;
width: 100%;
height: 100%;
overflow: scroll;
}
.main {
width: 1500px;
height: 1500px;
background-color: rosybrown;
display: flex;
flex-direction: column;
}
<nav class="navbar"></nav>
<div class="window">
<div class="control">
</div>
<div class="calendar">
<div class="wrapper">
<div class="main">
</div>
</div>
</div>
</div>