Relative sizing with CSS flex-shrink - javascript

I'm using flexbox to display several 3-4 widgets in a single vertical column. Each widget contains a table with a dynamic number of fixed-height rows. I'm trying to accomplish the following:
Widgets should auto-size to their content (remaining as small as possible) (flex-basis:auto)
Widgets should not grow (never appear larger than their content) (flex-grow:0)
Widgets should shrink (showing scrollbars) when the parent container is full (flex-shrink:>0)
Widgets should shrink relative to the size of their content (larger widgets should shrink more than smaller widgets) (flex-shrink:items.length)
Unfortunately, I'm having trouble with the last objective. I've tried using the item count as a value for flex-shrink, assuming it would shrink each widget relatively based on the number of items it contained. However, this doesn't work and leads to some strange/unexpected behavior.
Below is a code snippet demonstrating the issue (JSFiddle here: https://jsfiddle.net/87uwfkv3/5/). In this case (4 widgets of varying sizes) I'd like the second widget to show a single row (since it's only a single item), and the other 3 widgets to be (approximately) the same pixel height as one another with scrollbars.
const App = () => (
<div className="root">
<Widget count={60} />
<Widget count={1} />
<Widget count={600} />
<Widget count={40} />
</div>
);
const Widget = ({ count }) => (
<div className="widget" style={{flexShrink: count}}>
{new Array(count).fill(0).map((o,i) => (
<div key={i}>
item {i+1}
</div>
))}
</div>
);
ReactDOM
.createRoot(document.body)
.render(<App />);
html, body {
background: #aaa;
padding: 5px;
}
.root {
background-color: #ccc;
display: flex;
flex-direction: column;
height: 200px;
gap: 5px;
}
.widget {
background-color: #fff;
border: 1px solid black;
flex: 0 1 auto;
overflow-y: auto;
width: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>

Related

Force to scroll overflowing item in flexbox

Im making a container with 3 cards. Each card (brown-ish color in example) has a header with title (sand-buiscuit color) and content (blue one).
What I want to acheive is when the cards are closed (click on header in example), the content (blue) is transitioning to height 0, and so the only visible part is header.
Also when the card is open I want to show the available content but only then, when there is enough available space in container (green).
When 3 cards are open, they have the same height (expand evenly in container), and remaining content (blue) is scrolled.
Is it possible to make?
I prepared a demo codesandbox
I made a small code example using styled-components (just because i like it), you can easily change it to regular react components with css, but this demonstrates the idea.
I created 3 boxes, each box has a default height(40px) and after clicking (which opens it) its height is set to: 100%.
Wrapping all of this boxes with flex container does the trick.
import styled from 'styled-components';
import React, { useState } from 'react';
const MyComponent = () => {
return (
<Container>
<BoxContainer height={100} number={1} />
<BoxContainer height={100} number={2} />
<BoxContainer number={3} />
</Container>
);
};
export default MyComponent;
const Container = styled.div`
display: flex;
flex-direction: column;
justify-content: flex-start;
width: 200px;
height: 400px;
overflow: hidden;
border: 1px solid black;
background-color: blue;
`;
const BoxContainer = ({ number, height = '100' }) => {
const [open, setOpen] = useState(false);
return (
<Box style={{ height: open ? '100%' : '40px' }} onClick={() => setOpen(!open)}>
Box: {number}
{open && <p>Content</p>}
</Box>
);
};
const Box = styled.div`
width: 100%;
overflow: scroll;
background-color: #00b8a2;
border: 1px solid red;
`;
sandbox example here: https://codesandbox.io/s/boxes-fill-container-evenly-when-opened-btlvb

Making "View" fill upp entire screen in React Native

I am working on a React-native project and stumbled upon issues when setting width and height using percentage values to a View. I have tried to set width: 100% and height: 100% but this does not work.
function CalendarPage() {
return (
<MainWrapper>
<SafeAreaView style={styles.container}>
<ScrollView>
<StyleContentWrapper>
<Paragraph> Hello World! </Paragraph>
</StyleContentWrapper>
</ScrollView>
</SafeAreaView>
</MainWrapper>
);
}
const MainWrapper = styled.View`
flex: 1;
justify-content: center;
align-items: center;
background-color: lightgray;
color: white;
`
const StyleContentWrapper = styled.View`
height: 100%; // this does not work
width: 100%; // this does not work
background-color: red;
padding-top: 40px;
padding-horizontal: 20px;
`
A quick explaination for the components:
MainWrapper covers the entire screen and is the base layer. The reason why it nests SafeAreaView is because this allows me to set a background color on the "safe area".
I have also nested another view called StyleContentWrapperinside a ScrollView, because I want everything inside to be scrollable.
This is the results
StyledContentWrapper or The red box does not cover the entire screen, despite having the styles of width: 100% and height: 100%. Why is this? Setting fixed width and height does work, but this is not the approach I want, because different devices has different widths and heights, and I want it to work for multiple screens with different widths and heights, hence the use of perecentage.
How can I solve this?

Modal positioning in css grid system

I am trying to centrally position a modal whose button is clicked in grid column 2. Can anyone please point me in the right direction. I wouldn't want to hard code any margins ofcourse (responsive).
Right now it (green div) is only showing up / restricted to grid-column 2 as seen below .
display: grid;
grid-template-columns: 1fr 1fr;
height: 100%;
margin: 10px;
class Login extends Component {
state = {
isShowModal: false
};
openModal = () => {
this.setState({ isShowModal: true })
}
render() {
const { isShowModal } = this.state;
return (
<>
<div className="grid-1">
</div>
<div className="grid-2">
{isShowModal && <Modal />}
<div className="add">
<button onClick={() => this.openModal()} type="button">Open modal</button>
</div>
</div>
</>
)
}
}
Hi I think what you are looking for is Width max-content with some padding and margin 0px auto.
margin: 0px auto;
width: max-content;
padding: 10px;
max-width:100%; //for responsive purposes.
Then make a surrounding div and position it fixed. And apply the above styles to the divs inside your surrounding div
What this is doing is making a surrounding div that you can design your stuff inside of that will be centered.
Side Note: If you div is falling underneath other elements just set the z-index to 1.
z-index:1;

Animate shrink and expand transitions for subsets of elements in a nested set of divs in javascript [duplicate]

This question already has answers here:
How can I transition height: 0; to height: auto; using CSS?
(41 answers)
Closed 5 years ago.
I need to animate the shrink and expand transitions for subsets of elements in a nested set of divs. The expand works fine, but the shrink is broken.
I have a structured collection of items (say, squares for purposes here) that I want to display selectively and whose transitions I want to animate.
The structure is: collection > groups > rows > squares
In static layout,
squares appear in horizontal rows;
rows are gathered vertically in groups;
a column of groups forms the collection.
Squares can be of varying sizes, so containers must adjust accordingly
(no fixed heights or widths).
I have obtained a static layout that is just what I want.
The problem comes with animation. I want to hide various subsets
of squares, rows and/or groups. Nearby items can look similar so it is
difficult for users to tell just what is being added or subtracted, so
I need a smooth animation so users can follow what is changing.
I am trying to do this with a CSS-animated shrink:
A shrinkMe class marks all element that I will want to
shrink/expand at the moment
CSS transition times are set for these
shrinkMe elements
A shrunken class is defined whose CSS has all its
size parameters set to 0
To shrink or expand, jQuery adds or removes
the the shrunken class tag to the $('shrinkMe') items, to animate
items between the full and shrunken (=0) sizes
The un-shrink animated transition is exactly what I want. But the shrink animation does not work at all - contents spill out of containers along the way.
shrink = function(bool,nsec) {
$('.shrinkMe').css("transition", 'all ' + nsec+ 's');
if (bool) $('.shrinkMe').addClass('shrunk')
else $('.shrinkMe').removeClass('shrunk');
}
anim = function(secs) {
return 'all ' + secs + 's'
}
.controls {
display: inline-block;
vertical-align: top;
}
.collection {
display: inline;
text-align: center;
border: 2px solid black;
padding: 3px;
display: inline-block;
}
.group {
display: block;
margin: 2px;
border: 2px solid black;
padding: 3px;
}
.row {
display: block;
vertical-align: middle;
background: #0cc;
margin: 1px;
border: 2px solid black;
}
.sq {
display: inline-block;
background: white;
width: 20px;
height: 20px;
margin: 5px;
border: 2px solid black;
}
.lg {
width: 25px;
height: 25px;
}
.shrinkMe {
border-color: red;
}
.shrunk {
height: 0px;
width: 0px;
border-width: 0px;
padding: 0px;
margin: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<div class='controls'>
<button type='button' onclick='shrink(true,2)'>shrink reds </button>
<br>
<button type='button' onclick='shrink(false,2)'>unshrink reds </button>
</div>
<div class='collection'>
<div class='group'>
<div class='row '>
<div class='sq'></div>
<div class='sq'></div>
</div>
<div class='row shrinkMe'>
<div class='sq lg shrinkMe'></div>
<div class='sq shrinkMe'></div>
<div class='sq lg shrinkMe'></div>
</div>
</div>
<div class='group shrinkMe' id='group2'>
<div class='row shrinkMe' id='group2container2'>
<div class='sq shrinkMe'></div>
<div class='sq shrinkMe'></div>
</div>
<div class='row shrinkMe'>
<div class='sq shrinkMe'></div>
<div class='sq lg shrinkMe'></div>
<div class='sq shrinkMe'></div>
</div>
</div>
</div>
Among other things, I've tried using different explicit transition speeds, so containers shrink more slowly than their contents, but to no avail. If I set explicit heights and widths of the rows and groups, I can get a coordinated nested-shrink but it is ugly:
It shrinks by squashing to the left side and;
The final layouts can have empty spaces in them (e.g., when a row shrinks inside an unshrunk group, the fixed explicit group container height means there is now a hole where the row was).
What I want is to achieve is simple: a shrink animation that is the time-reverse of the nice clean un-shrink.
Here also is a jsfiddle showing the problem that additionally has buttons for trying separate timings of more deeply nested divs (which
does not help...)
https://jsfiddle.net/furnas/dgq8yusy/
Any explanation of what is going wrong and suggestions on how to fix
it?
Use jquery anymation onComplete event for adding and removing classes to divs.
because your css transition works like asyncronous method on another thread, so, you need to wait for it to complete and than add/remove classes.
http://api.jquery.com/animate/

Stacked divs resizing each other

This is probably going to be a long one:
I'm trying to make a chat application (similar to Slack) with Electron, React and Socket.io. My issue is mostly dealing with React and CSS/Sass though. Right now I've got a few bootstrap, but I'm not really using the grid system at all, so that can/may be scrapped.
The structure of the page is as follows: I've got a footer with a resizable textarea. above it I've got a div that will be holding messages. That div has overflow-y set to scroll, that way the scrollbar is only for the messages and doesn't take the entire page's space. I want the div to get shorter as the footer grows with the textarea. Right now though the div just extends under the footer (and the scrollbar along with it). Since the messages fill the div there's nothing to scroll and no thumb (I think that's the correct term) in the scrollbar.
React component (I've only included one li for the sake of brevity, but in my code I've got bunch):
import React from 'react';
import { Button, Image, Media, Panel } from 'react-bootstrap';
export default class Page extends React.Component {
constructor(props) {
super(props);
this.state = props;
}
footerResize() {
// code to resize messages div, or at least get some information about
// the footer's height
}
render() {
return (
<div className="page">
<div className="sidebar">
</div>
<div className="container-fluid">
<div classname="messages">
<ul>
<li className="message>
<Media>
<Media.Left>
<Image src="#" />
</Media.Left>
<Media.Body>
<Media.Heading>
Name
</Media.Heading>
Message content
</Media.Body>
</Media>
<li>
</ul>
</div>
<footer>
<textarea defaultValue="test text" />
</footer>
</div>
</div>
);
}
}
_page.scss (most of this is from the file name _page.scss but a few properties are pulled in from other files here so I'm only typing one file's contents):
$dark-grey: #383838;
$default-font-color: #FFFFFF;
$light-grey: #474747;
$light-light-grey: #908E8F
$sidebar-width: 250px;
body {
color: $default-font-color;
overflow: hidden;
}
ul {
list-style: none;
}
.page {
background-color: $light-grey;
height: 100vh;
.sidebar {
background-color: $light-light-grey;
position: fixed;
height: 100%;
width: $sidebar-width;
.container-fluid {
margin-left: $sidebar-width;
padding-left: 0px;
padding-right: 0px;
.messages {
overflow-y: scroll;
}
footer {
background-color: $main-green;
bottom: 0;
padding-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
padding-top: 10px;
position: fixed;
width: calc(100% - #{$sidebar-width});
}
}
}
}
I've tried a bunch of different things to get this to work. I've tried a few node modules. I've tried adding event listeners both by adding ref='footer' to the footer and referring to it as this.refs.footer in when adding the event listener and by giving footer and id and using document.getElementById('footer'). The whatever I try I can't get any information about the footer's size in the footerResize. Any help on this would be appreciated. I don't even know if this is something I should be doing with sass properties or whether I need js/React to do this.
You can try out a flexbox based layout.
This for .container-fluid
display: flex;
flex-direction: column;
This for .messages
flex: 1;
Then you remove position: fixed from footer
What this does: it sets the height of .messages to fill its parent's remaining space. So when footer gets bigger, there is less remaining space and .messages will shrink.
Please note that you will need to add vendor prefixes for flexbox depending on your targeted browser support.

Categories

Resources