Why putting the padding in percentages of an element put inside a parent which is inside a flexbox displaces the content? - flexbox

I am asking about this behavior. Elements inside a flexbox assume certain width according to their contents. So if we put an element (let’s call this the “child”) inside an element (and let’s call this the “parent”) put in a flexbox (we’ll just refer to this as the “flexbox”) and give the child a padding in pixels ,then the parent will be upsized according to the increase in the content of the child element. But surprisingly this is not the case when we use padding in percentages (we see the parent width stays the same and the child is pushed of the parent, it is like the padding is put on the inside of the parent element like we have used the rule of (box-sizing: border-box) and determined the width of the parent, but we didn’t). Why is this the case???
This is the HTML:
<div class="flexbox">
<div class="parent">
<div class="child">Hello World!</div>
</div>
</div>
This is the CSS:
.flexbox {
background: #EEE;
display: flex;
}
.parent {
background-color: red;
color: white;
}
.child {
padding: 5%;
}

Related

Styled components and scoping

I'm starting to work with styled-components and had a question about scoping.
This is just a dummy example but one that shows the point.
So I have a component. I setup a styled div called Wrapper then instead of creating another styled component to handle group, I thought be easier to just add a class to the inner div called .group and using nesting like in SCSS to style the inner div. This works but the problem with using className for the inner div is there could be a collision with global styles called .group
So, is there a way to avoid this with scoping somehow, or would I have to create another styled component called Group to handle that inner CSS ? Seems like a lot of boilerplate to have to add another styled component just to style the inner components.
const Wrapper = styled.div`
color: blue;
.group {
padding: 10px;
color: green;
}
`
const MyComponent = () => {
return (
<Wrapper>
<div className='group'>
<h1>heading text</h1>
<h2>subheading text</h2>
</div>
<div>This is my blue text</div>
</Wrapper>
);
}
Here is my globalStylesheet with group. Obviously this only has one style but it could have way more to handle grouped elements globally.
export default createGlobalStyle`
h1, h2, h3, h4, h5, h6 {
font-family: '.....';
}
.group {
background-color: red;
}
`;
I know I could also do
> div {
border: 1px solid red;
}
but I want to be able to be more explicit with a className
I think it's better to create another styled-component for group like
const Group = styled.div`
padding: 10px;
color: green;
`
So you can be sure that overwriting styles properly. And if there will be more styles in Wrapper, it stays less readable. Also you can easily replace Group component into children or make as parent(in this case you should rewrite .group style from Wrapper to another one).
In future to prevent boilerplate code you can rewrite existed styled-components like
const Timer = styled.div`
background: #ff5f36;
border-radius: 50%;
width: 48px;
height: 48px;
display: flex;
justify-content: center;
align-items: center;
font-family: GTWalsheim;
font-size: 32px;
color: #ffffff;
`
const TimeIsUp = styled(Timer)`
width: 172px;
border-radius: 8px;
`
EDIT
Also you can easily replace Group component into children or make as parent
I'll try to explain in code below
const MyComponent = () => {
return (
<Wrapper>
<div className='someClass'>
<Group> // so you can replace only your component, without rewriting any style
<h1>heading text</h1>
<h2>subheading text</h2>
</Group>
</div>
<div>This is my blue text</div>
</Wrapper>
);
}
I mean you can easily replace Group component to any place of code. While when you write style from parent as it was in Wrapper, you should replace this .group style from Wrapper to another element which is parent for .group

css grid: children items do not extend to full height

I have a grid container div (display: grid) which is inside a full height (flex) parent:
.scss file
.parent { /* this layout is full height */
display: flex:
flex-direction: column;
.layout-grid {
flex: 1; /* this makes my grid to take all available height of parent */
display: grid;
grid-template-columns: 20% 1fr;
grid-template-rows: 1fr;
grid-template-areas:
"left main"
"left main";
}
.left { /* this child is not full height*/
grid-area: left;
}
.main { /* this child is not full height */
grid-area: main;
}
}
.tsx file
<div className='parent'>
<div className='layout-grid'>
<div className='left'> Left </div>
<div className='main'> Main </div>
</div>
</div>
Here is the result:
The outer blue border is .layout-grid (display: grid) which is properly full height.
But I can't get the children of my grid to extend full height even if the grid is properly full height. I have tried justify-items: stretch with no success.
But if I give the .layout-grid a specific, defined height, not flex:1 nor height: 100% but a specific value (e.g height: 90vh), then children content expand to full height.
Is this the way css grid is supposed to work? (in other words: in order for children to take up full height, the grid parent container should have a specific value (not flex:1 or %) )? or there is a mistake somewhere in my style?

Flexbox and the <header>, <main>, and <footer> tags

I've read in a few places that when using flexbox, you should have all content in a <header>, <main> and <footer> tag for flexbox to work its magic. Is this true? Are these tags needed?
No. See the abstract of the spec:
The specification describes a CSS box model optimized for user
interface design. In the flex layout model, the children of a flex
container can be laid out in any direction, and can “flex” their
sizes, either growing to fill unused space or shrinking to avoid
overflowing the parent. Both horizontal and vertical alignment of the
children can be easily manipulated. Nesting of these boxes (horizontal
inside vertical, or vertical inside horizontal) can be used to build
layouts in two dimensions.
CSS is a language for describing the rendering of structured documents
(such as HTML and XML) on screen, on paper, in speech, etc.
Flexbox is part of CSS, which is a language independent of HTML. So saying it requires some HTML elements makes no sense.
Here you have a working example which doesn't use those elements:
div { display: flex; }
span { border: 1px solid; }
span:nth-child(1) { flex-grow: 1; }
span:nth-child(2) { flex-grow: 2; }
span:nth-child(3) { flex-grow: 3; }
<div>
<span>A</span>
<span>B</span>
<span>C</span>
</div>

why does this div leave a margin at the bottom

I am currently in learning CSS and it seems I have a hard time understanding the box model. I have a very simple page layout:
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" href="css/simpleimagebrowser.css">
</head>
<body>
<menu type="toolbar">
<ul>
<li>prev</li>
<li>next</li>
</ul>
</menu>
<div class="imagecontainer">
<img src="images/awsome.jpg">
</div>
</body>
</html>
and a very simple css:
body
{
margin: 0;
padding: 0;
}
menu
{
padding: 0;
margin: 0;
background: green;
}
ul
{
padding: 0;
margin: 0;
}
li
{
display: inline;
}
img
{
padding: 0;
margin: 0;
}
.imagecontainer
{
background: yellow;
padding: 0;
margin: 0;
}
Why is does my yellow <div> have this little margin or gap at the bottom?
I noticed that when I set the font-size to 0 that margin goes away. Can someone explain conceptually what's going on from a css/boxmodel perspective? It seems as if the browser is adding a blank text line below the image or something ...
Add display: block; to your image
img {
display: block;
}
The white space is due to the image being an inline element. I suppose it's the equivalent of line-heightwhich adds white space around text.
This is because all inline elements are expected to fit the 'contains text' model of a span tag, where space is reserved for the tails on letters like g, q, j, etc.
If non, this extra-space is used for 'link underlining' by default browser settings on inline level elements. Meaning, it reserves space for a link hover underline.
tail (n: tel)
Of a letter, the part that extends below the baseline and to the
right, as gjqy. Of the capital letters, Q and R have tails, though
they need not extend below the baseline.
Indeed, adding "display: block;" to your img rule will make the problem go away. This is most likely due to images being treated as "inline" or "inline-block" by default. Thus the browser is very likely attempting to work your image into the line-height of the parent element.

How to fill the screen with a div, then center it once the screen gets too big (max-height reached)?

Goal:
When the width and height of the window are both small, the div should be the same size as the window;
When the width of the window is too big (>max-width), the div should keep its width as max-width, and be horizontally centered.
When the height of the window is too big (>max-height), the div should keep its height as max-height, and be vertically centered.
The example below has achieved everything, except for the last point.
How to center this div vertically in the window? I.e., I want the red areas to behave like the green ones, but just vertically instead of horizontally.
(This design is intended for a responsive design for mobile devices' screens. No JS involvement if possible.)
<!doctype html>
<html>
<head>
<style>
body,html{
height:100%;
margin:0px;
background:green;
}
#t1{
position:relative;
height:100%;
max-width:640px;
margin:0 auto;
background-color:red;
}
#t1-1{
position:absolute;
height:100%;
max-height:640px;
width:100%;
background-color:#dddddd;
overflow:hidden;/*demo purpose*/
}
/*the following stuff are for demo only*/
img{
position:absolute;
opacity:0.5;
}
img.w{
width:100%;
}
img.h{
height:100%;
}
</style>
</head>
<body>
<div id="t1">
<div id="t1-1">
<img class="h" src="http://www.google.com/images/srpr/logo3w.png" />
<img class="w" src="http://www.google.com/images/srpr/logo3w.png" />
</div>
</div>
</body>
</html>
P.S. In this example, some desktop browsers internally set a min-width value to the whole thing (e.g. 400px in Chrome), unabling the div to keep shrinking horizontally.
You may need a little javascript to make it work:
First of all, you need an <div> element to layout, so I called it mask:
<div id="mask"></div>
Then, style it to fill the entire document, and give a max-width and max-height:
<style>
#mask {
position: fixed;
height: 100%;
max-height: 400px;
width: 100%;
max-width: 400px;
top: 0;
left: 0;
background: red;
}
</style>
This style do not perform the centering work, so you need your javascript to do it, we have a layoutMask function to determine if the div should be centered or not:
var mask = document.getElementById('mask');
function layoutMask() {
// here 400 is the same as the max-width style property
if (window.innerWidth >= 400) {
mask.style.left = '50%';
// to ensure centering, this sould be (max-width / 2)
mask.style.marginLeft = '-200px';
}
else {
mask.style.left = '';
mask.style.marginLeft = '';
}
// the same as width
if (window.innerHeight >= 400) {
mask.style.top = '50%';
mask.style.marginTop = '-200px';
}
else {
mask.style.top = '';
mask.style.marginTop = '';
}
}
At last, assign this function to the resize event, and execute immediately to ensure the <div> got layed correctly on first load:
if (window.addEventListener) {
window.addEventListener('resize', layoutMask);
}
else {
window.attachEvent('onresize', layoutMask);
}
layoutMask();
I tried this on my chrome, but I'm sure it does not work under IE6 since IE6 doesn't support the position: fixed; style, but it should work in most browsers.
I've made a jsfiddle for test.
As per my knowledge, with height:100% it is not possible. You need to use <center> to keep it in center horizontally and vertically. You may need to use margins also. Like:
margin-top:18%;
margin-left:40%;
You can add a #media query to achieve this effect
#media (min-height: 640px) {
#t1-1 {
top: 50%;
margin-top: -320px;
}
}
See JSFiddle for testing.

Resources