Component whose children can fill it - css

I marked this question with "react" tag, however, I think that framework does not matter so much in this case.
I have a component, whose job is to display some children. All this component does is it displays some styling - a border and a background - so it's just a box.
This box could be displayed "dynamically", so no static height would be specified - it could be "flex-grow: 1" for example.
How to make the children fill this component entirely?
This is my Box:
class Box extends Component {
render() {
return (
<div className={"box " + this.props.className}>
<h2>BOX</h2>
<div>{this.props.children}</div>
</div>
);
}
}
Here are its styles:
.box {
border-width: 5px;
border-color: black;
border-style: solid;
background-color: purple;
}
Ideally, child would just set "height: 100%", but this will not work, because Box does not define any height.
One solution would be to set "display:flex" on the div inside of which "{this.props.children}" is placed. However, this requires children to use "flex-grow: 1" - I think it's not best solution, because children shouldn't know how Box is implemented. It also makes the problem recursive - children of my children again need to use flex-grow...
//EDIT
Here's an example: https://codesandbox.io/s/nervous-sunset-bvhjh
Box-content should fill the whole place that it has in a Box, but it does not. How to achieve that?

You can achieve that in pure css (this way, children do not need to be aware of the flex mode of their parents) :
.row2 {
flex-grow: 1;
display: flex;
flex-direction: column;
}
.row2 > div {
flex-grow: 1;
}
by styling all the child divs.
a codesandbox to see the result

Related

i want to know how i program fix-height-div and flexible-height-div

I have a programming website in CSS. During programming, I found one problem.
if display-size is changed, under div is rising. so, I want to solve this problem to add sub-div when display-size is changed. in the picture which i attach, i only want to show div 1, and when user scroll, show other under div. and when display-size is changed, i add sub-div(=div2 in the picture). (div 1 background color and div 2 background color is same. so it seems that it is only div 1. because of the same color) how should I program this?
I am not able to understand you question proper, but as per scenario given in attachment following things you need to do
.div1 {
height: 200px //fixed height for div1
}
.div2 {
display: none;
height: auto;
}
and using jquery you can target on scroll event to show div2
$(document).on('scroll', function(){
if($(window).pageYOffset > 0) {
$('.div2).show();
}
else {
$('.div2).hide();
})
and for mobile write media query
#media only screen and (max-width:768px) {
//write your css code for div1 and div2 here.
}
I am not getting clearly what you want to achieve, but if your goal is to combine a fixed-size element, and give the rest of the space to an other, flexible element, flexbox could help:
<div class="parent">
<div class="fixedSizeDiv"></div>
<div class="flexibleDiv"></div>
</div>
with styles like:
.parent {
/* maybe height property need to be set, depending on your wrapper element layout properties... */
display:flex;
flex-direction:column;
}
.fixedSizeDiv {
flex-basis: 200px; /*or whatever*/
}
.flexibleDiv { flex:1; }

Text Input Responsive Width - Bootstrap 3

Setting:
I have a input type="text", a label and a custom checkbox with its own label inside a span to encapsulate them, inside a div on a li.
Styling:
input type="text" has aesthetic styling only.
label has margin-left:5px;
span has display: inline-block; float: right;
div has classes form-group and form-inline from Bootstrap 3.3
Problem:
The label is initially empty but once I type something in the input, a script will run, filling in that same label with text.
I've been trying to set the width of the input to be auto, having it's width the same as the container it's in, reaching the span, so that when the label appears, it shortens itself out.
Instead, the input remains small. I think I'm doing something wrong but even with some research, I can't understand what it is exactly.
I've tried removing the classes from the div (wich just breaks it), apply width=100%;, wich, makes it large, but pushes it and the label to the line below.
Could someone provide some help, please?
Here is how it looks below:
without text
with text added by js
Link to Codepen.
You need a wrapper around the input and label using calc to set width 100% - (arbitrary amount to allow for checkbox), e.g.
.listWrapper {
width: calc(100% - 75px);
}
You can then set this .listWrapper to display: flex, and give the input flex: 1 1 auto so that the input will grow/shrink as required to take up all available internal space minus whatever space the label requires. You can set flex-wrap to nowrap so it all remains on one line.
Here's an updated codepen:
https://codepen.io/anon/pen/ZXwxKz
The relevant updated styles are here, so you don't have to pick through everything:
.listWrapper {
width: calc(100% - 75px);
float:left;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
}
.listWrapper .listInput {
flex: 1 1 auto;
}
You may also need to use a clearfix on the wrapper due to the floats. If you have a clearfix style already, apply it to ".form-group.form-inline", if not, add this style to your CSS:
.form-group.form-inline:after {
content: "";
display: table;
clear: both;
}

100% height body is taller than 100vh, caused by Angular's router-outlet

I have an angular page, home, which is comprised of 2 components and a router-outlet
<div class="home-container">
<header></header>
<sub-header></sub-header>
<router-outlet></router-outlet>
</div>
I want the home-container above to always be, at a minimum, full screen height. The header should show, then the sub-header, then the contents of the router-outlet should always fill up at least the rest of the screen (or more if there's more content of course).
Normally this is easy but it seems the router-outlet is messing it up. Example can be seen http://plnkr.co/edit/56k9ZabLAGujBoX8Lsas , hit run and then click the "Heroes" link to route. In this example I don't want the Heroes div to be taller than the screen, and don't understand why it is.
My styles to accomplish this are. (assume router-outlet is on 'my-page')
html, body {
height: 100%;
}
.home-container {
height: 100%;
}
.my-page {
height: 100%;
}
My expectation here obviously is that home-container is full screen, shows header, shows sub-header, and that my-page then fills in at a minimum the rest of the vertical height.
What is actually happening though, is that there's a scroll bar with available height that appears equal to my header and sub-header.
This plnkr http://plnkr.co/edit/56k9ZabLAGujBoX8Lsas illustrates exactly my meaning. If you click Run and then the link for "Heroes" you will see the router-outlet contents, in this case heroes-list.component, with a green background. I do not understand why the green here is bleeding below the screen when everything is set to 100%
Update I have tried using all manner of different CSS attributes to different levels in this nesting. Including 100vh vs 100%, min-height vs height, and every combination of body/html/home-container/my-page. I have also tried the same with Angular's CSS :host, to the same result of no different
Update2 If I move it out of the element then everything behaves as you'd expect and there's no vertical scroll bar. Something about the router-outlet wrapper adds vertical space somewhere but I cannot figure out where or what is causing it.
Final Update The below answers might be useful for some applications but I ended up just solving it by giving the .my-page a specified height, just doing height: calc(100vh - $headerheight - $subheaderheight) which gets the job done
As far as I understand, 100% on a child will be equal to the size of the parents natural height. If you want to fill the space available, you really should be using flex unless you have a requirement to support IE9 and below.
I would update your Anchors to be contained in a div (or another wrapper)
<h1 class="title">Component Router</h1>
<div>
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
<a [routerLink]="['Heroes']">Heroes</a>
</div>
<router-outlet></router-outlet>
I would then utilize flexbox to allow the content to expand as required
.hero-list {
background-color: green;
height: 100%;
overflow:auto
}
undefined {
flex: 1;
}
body, html, my-app {
height: 100%;
}
my-app{
display: flex;
flex-flow: column;
}
Plunker to test: http://plnkr.co/edit/yE1KOZMr1pd5jQKlVYIN?p=preview
On chrome i still have scroll bars due to an 8px margin on body - this can easily be removed with CSS for a scroll free full height experience.
There are two causes that make your <body> element taller than 100% of the viewport:
Default margins of the <body> element that come from the browser's built-in styles and usually are 8px. This means that the <body> element will be as tall as the <html> element, but also will have 8px space above it and below it, causing the <html> element to overflow.
The top margin of the <h1> element "falls out" from the container due to margin collapsing. This makes the space above the <body> element equal to the default top margin of <h1> (about 21px instead of 8px).
Setting zero margin to <body> (part of ToTaTaRi's answer) helps you to solve the 1st issue. To solve the second one, you should make the <body> element or (probably better) the .my-app container establish the new Block Formatting Context. The easiest and most cross-browser way for this is setting the container overflow:hidden (other options are display:flow-root, which works for modern Chrome/Firefox, or column-count:1, which works in IE10+ and all modern browsers, you can compare nearly all the options in this live example).
First of all you should reset browser default styles at least somehow like this:
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
Then you could achive what you want without a flex layout if prefered through splitting the page into a header section and main content section with a preset division... So lets say the heading and the links go together into a container div with i.e. a height of 20% and the main content which is at the moment hold in a tag "undefined" gets a height of 80%, if you now set the height of the app container to 100% or 100vh it should work as expected!
EDIT (because the topic is still open...):
Have you tried this css code like explained above, works like charm!?
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body, my-app {
height: 100%;
height: 100vh;
}
h1 , h1 + div {
height: 10%;
height: 10vh;
}
undefined {
display: block;
background-color: green;
min-height: 80%;
min-height: 80vh;
}

How do I reduce the white space under the topnav?

On this site http://exact-mats.myshopify.com/ we want the height of the white space above the logo to equal the height of the whitespace below it.
I can't find the CSS rule to make this happen.
I can see we need to target something in
<nav class="top-menu">
....
<div class="row">
What am I missing? What CSS do I change?
Thanks.
add
padding-bottom: 0;
for the row below the div
<div class="free-shipping">Free shipping on all orders</div>
it did work when i inspected and added padding-bottom: 0;
Remove margin bottom from label and select inside <div class="car-search"></div>
.car-search label, .car-search select {margin-bottom: 0}
Set a height to the parent div of ".large-menu-container" which is ".row" or just add another parent to it if you don't want to modify the ".row".
I set the height to 75px and it works.
When you use "height: 100%;" on an element, its parent must have a predefined height in order to work.
Then you will have to adjust the select tags with a margin/padding top
Snapshot of new CSS
Add margin-bottom: -30px; In
.top-menu .row {
max-width: 82.5rem; }
Of your exact-mats.myshopify.com css
If you are unable to change css because of using third party CSS then
add new CSS class in
1. Every page where you are showing your Logo
2. OR if you can, add this class to custom .css file.
.top-menu .row {
margin-bottom: -30px; !important }
Note: I would rather suggest increasing the height of white space above top nav so it will look better than reducing space below it.
To do above thing.
Either add following CSS.
.top-menu .row {
padding-top: 31px !important; }

Allow absolutely positioned element to be wider than parent absolutely positioned element

Background
I have a small one-level CSS flyout menu (well, technically it's an expanding element). It is absolutely positioned at the bottom left of a parent absolutely-positioned element that is fairly narrow. See the second h1 element below:
<div id="controls">
<h1>Controls 1</h1>
<h1 id="size" class="poplinks button">
Size
<img src="">
<img src="">
<img src="">
</h1>
</div>
This is very simply turned into an expanding menu/flyout like so:
.poplinks:hover {
width:auto;
}
.poplinks a {
display:none;
}
.poplinks:hover a {
display:inline-block;
}
Problem
This results in the following button-like element:
The h1 has style width:48px;, and there is also a style rule to apply width:auto; to the h1 element upon hover, so it should be able to widen. However, upon hovering, the submenu is being forced to stay no wider than the parent element's width, when I'd like it to extend to the right (out of the parent's containing box).
What I want to see (obtained by moving the element outside the parent, but I would like it to remain inside for inheriting styling and so when I move the menu bar from the left to the top, it follows automatically):
Is this possible? Do you have any recommendations?
See this in action for yourself in a JS Fiddle.
Browsers
Note: I plan for this to work in Firefox, Chrome, and IE 8. I am doing the main styling in Firefox & Chrome and when basically done, will add conditional CSS to get IE to work right and look as close as I can.
Rationale
The reason I am positioning the parent menu absolutely is that I'm building an application-like page for displaying images. The page will be hosted within a parent Windows application and doesn't need a lot of identifying information: just to display the desired images. I chose to make the menu absolutely positioned rather than using inline-block or floats or some other method to get my menu columns into place (there are two). However, it doesn't have to be this way. If you have a suggestion for an alternate layout or strategy, I am all ears.
First, your #controls need overflow:visible. Then, #size should be given an explicit left instead of right. And finally, .poplinks needs white-space: nowrap to prevent the wrap.
http://jsfiddle.net/VaWeK/11/
I'm writing this answer because I might need it again in the future.
Although I've found this in the selected answer, it also mentions lots of other details asked by OP, and that somehow ended up hiding what was the important part to solve my problem.
What did the trick for me was the: white-space: nowrap.
I needed this for a dropdown component, which I think is a common use case.
The code below uses React and styled-components.
const styled = window.styled;
const LS = {};
LS.DropdownButton_DIV = styled.div`
position: relative;
width: 150px;
height: 30px;
display: flex;
align-items: center;
padding-left: 8px;
border: 1px solid silver;
user-select: none;
cursor: pointer;
margin-bottom: 100px;
`;
LS.Dropdown_DIV = styled.div`
position: absolute;
left: 0;
top: 100%;
display: ${props => props.open ? "block" : "none"};
`;
LS.DropdownItem_DIV = styled.div`
display: flex;
padding-left: 8px;
border: 1px solid silver;
/* THIS IS WHAT SOLVES THE PROBLEM */
white-space: ${props => props.noWrap ? "nowrap" : "initial"};
`;
function App() {
const [open1,setOpen1] = React.useState(false);
const [open2,setOpen2] = React.useState(false);
function toggleDropdown1() {
setOpen1((prevState) => !prevState);
}
function toggleDropdown2() {
setOpen2((prevState) => !prevState);
}
return(
<React.Fragment>
<LS.DropdownButton_DIV onClick={toggleDropdown1}>
Dropdown Button 1
<LS.Dropdown_DIV open={open1}>
<LS.DropdownItem_DIV>
Dropdown Item Longer Than Parent
</LS.DropdownItem_DIV>
</LS.Dropdown_DIV>
</LS.DropdownButton_DIV>
<LS.DropdownButton_DIV onClick={toggleDropdown2}>
Dropdown Button 2
<LS.Dropdown_DIV open={open2}>
<LS.DropdownItem_DIV noWrap={true}>
Dropdown Item Longer Than Parent
</LS.DropdownItem_DIV>
</LS.Dropdown_DIV>
</LS.DropdownButton_DIV>
</React.Fragment>
);
}
ReactDOM.render(<App/>, document.getElementById("root"));
* {
box-sizing: border-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<script src="//unpkg.com/styled-components#4.0.1/dist/styled-components.min.js"></script>
<div id="root"/>
Two ways: you can either hardcode an absolutely defined width, or you can do a relative width that is greater than 100%. Width of 100% will be 100% of the containing div (as long as that div has a defined width). If this div has an absolute width, meaning it is defined with pixels instead of percentages or ems, then you can simply make the hover css wider than the parent div. For example, if your parent div is 100px wide, the hover on the child should be 200px wide or 200% or something like that.

Resources