I am creating a web page which needs has to display some movie covers all in a single page, without scrolling it, becouse it will be on display. the problem is that i want to get the content to resize instead of making the web page scrollable. I also need to support n movies (they are dependent). I've tried using flexbox twice, but it doesnt work. Also, I am using tailwindcss framework, but i don't think that's a problem as it is just css in form of classes...
<html class='h-full m-0 p-0'>
<head>
<link href="https://unpkg.com/tailwindcss#next/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class='h-full m-0 p-0'>
<div class='mx-10 mt-10 flex content-center items-center'>
<div class='flex flex-wrap'>
<!-- iterate over every movie -->
<div class='m-2 relative flex-grow h-full' style='flex-basis: 20%'>
<span class='px-2 py-1 rounded-full bg-blue-500 text-white absolute z-0' style='top: -0.5rem; right: -0.5rem'>0</span>
<img src='https://images.unsplash.com/photo-1525604803468-3064e402d70c' class: 'w-full' />
<span class='w-full opacity-75 bg-black text-white py-1 absolute z-0 inset-x-0 bottom-0 text-center px-2'>title</span>
</div>
<!-- end -->
</div>
</div>
</body>
</html>
EDIT: I added a the full example (with an example image take from unsplash) of what i want it to look like.
I don't think there is a way to do what you are asking without JavaScript. In the following example, I used CSS to maintain the ratio of the covers, and used JavaScript to calculate the maximum width that would keep the content from scrolling vertically.
Here is a fiddle.
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
let numCovers = 10;
let coverList = document.querySelector(".cover-list");
// this function determines what percentage of the cover-list's width
// each cover should take up. It will maximize how large they can be
// without making the total grid size larger than cover-list.
// This should prevent scrolling.
function getBasis() {
let ratio = 1.35; // height/width
let width = coverList.clientWidth;
let height = coverList.clientHeight;
// this loop is really slow, you may want to find a faster way
let col = 0;
let accWidth, accHeight, numRows;
do {
col++;
if (col > numCovers) {
// maximize height
return (height / ratio) + "px";
}
accWidth = width / col;
accHeight = accWidth * ratio;
numRows = Math.ceil(numCovers / col);
} while (accHeight * numRows > height);
return (100 / col) + "%";
}
function generateCovers() {
// clear existing covers
coverList.innerHTML = "";
let basis = getBasis();
for (let i = 0; i < numCovers; i++) {
let cover = document.createElement("div");
cover.classList.add("cover");
cover.style.flexBasis = basis;
let inner = document.createElement("div");
inner.classList.add("inner");
inner.style.backgroundColor = getRandomColor();
cover.append(inner);
coverList.append(cover);
}
}
let numCoversInput = document.querySelector("#num-covers");
numCoversInput.addEventListener("change", function() {
numCovers = Math.min(Math.max(this.value, 1), 500);
this.value = numCovers;
generateCovers();
});
generateCovers();
window.addEventListener("resize", function() {
let basis = getBasis();
coverList.querySelectorAll(".cover").forEach(function(el) {
el.style.flexBasis = basis;
});
});
body {
/* set margin to computable value for cover-list calcs */
margin: 5px;
}
#controls {
height: 25px;
}
.cover-list {
/* account for margin and controls with calc */
width: calc(100vw - 10px);
height: calc(100vh - 35px);
/* use flex so the content will wrap as desired */
display: flex;
flex-wrap: wrap;
align-content: start;
}
.inner {
/* padding percentages are based on width, so setting
the height to 0 and padding-bottom to a percentage
allows us to maintain a ratio */
width: 100%;
height: 0;
padding-bottom: 135%;
}
<div id="controls">
<label>
Number of covers: <input id="num-covers" type="number" value="10" min="1" max="500"/>
</label>
</div>
<div class="cover-list">
</div>
Related
I want to bind text font-size with text length (in <p> with fixed width for example). Expected result is text fit in one line if it is only one word. If there are few words, it can be few lines.
I want to reduce font-size if word is too long for fixed-width line. For example, if "abc" fit in line I want to do nothing, if "abcdefg" doesn't fit in line I want to reduce text font-size
You can use a simply div setting your personal width, inside set your text, in css use
display: flex;
flex-wrap: wrap;
That way the text will respect your div width and brake line in your text when necessary
flex-wrap
Hope this answer will satisfy your question.
The resizing part, which is the most important, is creditted to Jan Küster, with "Make text fit its parent size using JavaScript" article that you can find online.
document.getElementsByTagName("input")[0].onkeyup = execute;
function execute() {
let value = document.getElementsByTagName("input")[0].value;
let words = value.split(" ");
var html = "";
for (var i = 0; i < words.length; i++) {
html += ' <div class="text-container"><span class="text">' + words[i] + '</span></div>';
document.getElementsByClassName("parent")[0].innerHTML = html;
}
resizeText({
elements: document.querySelectorAll('.text'),
step: 0.25
})
}
//
const isOverflown = ({
clientWidth,
clientHeight,
scrollWidth,
scrollHeight
}) => (scrollWidth > clientWidth) || (scrollHeight > clientHeight)
const resizeText = ({
element,
elements,
minSize = 10,
maxSize = 512,
step = 1,
unit = 'px'
}) => {
(elements || [element]).forEach(el => {
let i = minSize
let overflow = false
const parent = el.parentNode
while (!overflow && i < maxSize) {
el.style.fontSize = `${i}${unit}`
overflow = isOverflown(parent)
if (!overflow) i += step
}
// revert to last state where no overflow happened
el.style.fontSize = `${i - step}${unit}`
})
}
body {
background: #A33;
}
.parent {
margin: 2%;
width: 150px;
height: auto;
min-height: 50px;
padding: 15px;
color: white;
display: block;
}
.text-container {
width: 100%;
height: 100%;
}
.text {
font-size: 12px;
display: block;
}
<input type="text">
<div class="parent">
</div>
You could check out Bootstrap 5, they now have responsive text incorporated.
You could also use media queries that change the text size when the screen size is smaller or larger:
/* If the screen size is 601px wide or more, set the font-size of div to 80px */
#media screen and (min-width: 601px) {
div.example {
font-size: 80px;
}
}
/* If the screen size is 600px wide or less, set the font-size of <div> to 30px */
#media screen and (max-width: 600px) {
div.example {
font-size: 30px;
}
}
A final option would be to use the viewport width as the font size. Viewport is the browser window size. 1vw = 1% of viewport width. If the viewport is 50cm wide, 1vw is 0.5cm. Here's an example:
<h1 style="font-size:8vw;">Hello World</h1>
<p style="font-size:2vw;">Resize the browser window to see how the font size scales.</p>
i am trying to put several images (five) next to each other in one row. The row should have the width of a 100%. It is important that the images all have the same height e.g.! Is there a way to manage this? I tried several code, e.g. a masonry, but it does not help me with the height of the images.
Thank you
(I am using Bootstrap if that's any help.)
Edited, new answer.
The code below should do the job.
Note that I have inserted comments between all the img tags in the html, this is to make sure that there is no spacing between the images and is therefore important for the code to work!
Also note that if you change the class of the div which contains the images, you will have to change the query selector in the javascript to match this.
Final note: the script is very laggy here in the code snippet. I tried it as an actual webpage and it was not laggy at all, so maybe try that too!
var repeat = true;
window.addEventListener("load", resizeImages);
window.addEventListener("resize", resizeImages);
function resizeImages() {
var i;
var images = document.querySelectorAll("div.row img");
var heights = [];
var widths = [];
for (i = 0; i < images.length; i++) {
heights.push(images[i].offsetHeight);
widths.push(images[i].offsetWidth);
}
var numerator = document.body.clientWidth;
for (i = 0; i < heights.length; i++) {
numerator *= heights[i];
}
var denominator = 0;
for (i = 0; i < widths.length; i++) {
var thisItem = widths[i];
for (i2 = 0; i2 < heights.length; i2++) {
if (i != i2) {
thisItem *= heights[i2];
}
}
denominator += thisItem;
}
var height = numerator / denominator;
for (i = 0; i < images.length; i++) {
images[i].height = height;
}
if (repeat) {
repeat = false;
setTimeout(function() {
resizeImages();
}, 300)
}
}
div.row {
white-space: nowrap;
}
<html>
<head>
<title></title>
</head>
<body>
<div class="row">
<img src="https://media.wired.com/photos/5926db217034dc5f91becd6b/master/w_1904,c_limit/so-logo-s.jpg" alt=""><!--
--><img style="padding-left:5px;" src="https://jessehouwing.net/content/images/size/w600/2018/07/stackoverflow-1.png" alt=""><!--
--><img src="http://www.andysowards.com/blog/assets/8-Best-Websites-That-Will-Hone-Your-Programming-Skills-7-1024x538.png" alt="">
</div>
</body>
</html>
I used CSS Grid for your implementation. .row is 100% width and each image can have its own custom scaling if need be.
Be aware, images are hard make constant because each image will come with its own ratio and size.
You can use background-size to set image property to your liking.
The background-size CSS property sets the size of the element's background image. The image can be left to its natural size, stretched, or constrained to fit the available space.
Hope the example below helps.
Reference background-size: https://developer.mozilla.org/en-US/docs/Web/CSS/background-size
Reference CSS Grid: https://css-tricks.com/snippets/css/complete-guide-grid/
img {
height: 130px;
width: 100%;
}
.row{
width: 100%;
display: grid;
grid-template-rows: auto;
grid-template-columns: repeat(5, 1fr);
/* If each individual picture column need modification*/
/* grid-template-columns: auto 1fr 200px 15px 10%; */
}
<div class="row">
<img src="https://loremflickr.com/cache/resized/8447_7961096220_79eb4fb07c_c_640_360_nofilter.jpg" alt="">
<img src="https://loremflickr.com/cache/resized/65535_40670884373_757596f5d1_b_640_360_nofilter.jpg" alt="">
<img src="https://loremflickr.com/cache/resized/65535_47957578362_73f1562d77_z_640_360_nofilter.jpg" alt="">
<img src="https://loremflickr.com/cache/resized/65535_46970967485_3456a6be5f_z_640_360_nofilter.jpg" alt="">
<img src="https://loremflickr.com/cache/resized/2544_3722368834_5584ab3bc1_z_640_360_nofilter.jpg" alt="">
</div>
On a normal width / size screen, I have a grid of 3 x 3 tiles that contain summary status information. I am using CSS Flex and all works very well on smaller screens, collapsing to a 2 column grid and finally a single column on mobile.
However, I am trying to figure out a way to have a click on any grid element open an expander beneath it with "extra detail". The expander should obviously be the full width of the screen.
So, for example, on a desktop, with a 3x3 grid, if I click on the first box, I want an expander to expand beneath the first row, filling the full width of the screen.
However, if I simply have a full width div display on click, it just pushes the 2nd and 3rd tiles down beneath. See image for better explanation!
Can anyone suggest a good approach here using flex?
Ok here's an updated Version:
Most of the stuff should be commented, but I'm pretty bad at explaining. So feel free to ask if anything is not clear.
For the HTML part:
You need to seperate your "Clickable" Item and the expandable container into two seperate flex items. The order of them doesn't matter
For CSS Part:
Simply give that expandable Container a width of 100% and hide them with display: none
Javascript (thats the tricky part):
1. For that item you clicked, you need the number of the current row's last item
2. isert the expandable flex item after that clicked
3. show the expandable
To have it reposition if you resize the window and get into another viewport, simply trigger the click again if the "items per row" is changing.
fiddle: https://jsfiddle.net/Hoargarth/mfg0vshL/
//click event to expand the expandable
$('.flex-item').on('click', function(){
//hide previous opened expandables
$('.flex-item').removeClass('active');
$('.flex-expandable').slideUp();
//get target data
var target = $(this).attr('data-target');
//toggle the container
var $triggered = $(this);
var $triggeredElement = $('.flex-expandable[data-target='+ target +']');
positionExpandableElement($triggered, $triggeredElement);
$triggered.addClass('active');
$triggeredElement.slideDown();
});
//we need to check on resize how many items are pe row, if it changes, trigger a click on a already opened item, so it positions itself at the right position
var containerWidth = $('.flex-container').outerWidth();
var itemWidth = $('.flex-item').outerWidth();
var itemsPerRow = Math.floor(containerWidth / itemWidth);
$(window).resize(function(){
containerWidth = $('.flex-container').outerWidth();
itemWidth = $('.flex-item').outerWidth();
var newItemsPerRow = Math.floor(containerWidth / itemWidth);
if(itemsPerRow != newItemsPerRow){
itemsPerRow = newItemsPerRow;
$('.flex-item.active').trigger('click');
}
})
function positionExpandableElement(triggered, element) {
/*first determine at which position your expandable element has to be, should be the first element of next row from triggered element.
For this we need to know how many elements currently are in a row. Then you can position it after that element*/
//get the item number where you have to insert after
var allFlexItems = $('.flex-item');
var itemsData = []; //we need an array of data-targets to get the number of element from the array index
$.each(allFlexItems, function(key, el){
itemsData.push($(el).attr('data-target'));
});
var elNumber = $.inArray($(triggered).attr('data-target'), itemsData)
//elNumber now tells us the position of the element that got triggered
//now we can calculate where we have to insert our expandable
var rowNumber = Math.floor(elNumber / itemsPerRow);
var insertAfter = (itemsPerRow * rowNumber) + itemsPerRow - 1; //we add itemsPerRow because we always need to skip the first row, -1 because array starts at 0
//now that we now the last items number (even in responsive), we can insert our expandable on click after that element
$(element).insertAfter($('.flex-item')[insertAfter]);
}
.flex-container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 100%;
}
.flex-item {
width: 100%;
height: 100px;
background-color: blue;
margin-bottom: 15px;
cursor: pointer;
}
.flex-expandable {
display: none;
width: 100%;
height: 100px;
background-color: orange;
margin-bottom: 15px;
}
#media (min-width: 400px) {
.flex-item {
width: 45%;
}
}
#media (min-width: 600px) {
.flex-item {
width: 30%;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- for data-target you can use anything you want. Even something like data-target="this-is-my-first-container", as long as the expandable got the same like the item and it should be unique -->
<!-- The order of the Items dosn't matter, you could even randomize them -->
<div class="flex-container">
<div class="flex-item" data-target="1"></div>
<div class="flex-item" data-target="2"></div>
<div class="flex-item" data-target="3"></div>
<div class="flex-item" data-target="4"></div>
<div class="flex-item" data-target="5"></div>
<div class="flex-item" data-target="6"></div>
<div class="flex-item" data-target="7"></div>
<div class="flex-item" data-target="8"></div>
<div class="flex-item" data-target="9"></div>
<div class="flex-expandable" data-target="1"></div>
<div class="flex-expandable" data-target="2"></div>
<div class="flex-expandable" data-target="3"></div>
<div class="flex-expandable" data-target="4"></div>
<div class="flex-expandable" data-target="5"></div>
<div class="flex-expandable" data-target="6"></div>
<div class="flex-expandable" data-target="7"></div>
<div class="flex-expandable" data-target="8"></div>
<div class="flex-expandable" data-target="9"></div>
</div>
The purpose of #hoargath need just one fix for the last incomplete line:
insertAfter = insertAfter > (allFlexItems.length - 1) ? allFlexItems.length - 1 : insertAfter;
I'm trying to make a circle out of images with different sizes and different shapes (some rectangle, some sqaure, some portrait, some landscape).
When I'm using: clip-path: circle(50% at 50% 50%); or border-radius: 50%;, it turns the image into a perfect circle, only if the image is square:
Is there a way to crop an image into a square and then use one of these methods to make it a perfect circle:
Using pure CSS withou using background-image (most images are given the background image from server side),
Keeping a 50% ratio - without losing aspect ratio - (both if border-radius or clip-path)(Images size may vary).
Here's a code snippet to show a square image and a rectangle image:
.clipped {
clip-path: circle(50% at 50% 50%);
}
Square<br>
<img src='http://i.imgur.com/d5byNNR.jpg' width="100" class='clipped' /><br><br>
Rectangle<br>
<img src='http://i.imgur.com/22W12EQ.jpg' width="100" class='clipped' />
You can use circle() but without the parameters:
.clipped {
clip-path: circle();
}
It appears to use the smaller side of your image as the circle's circumference.
Working sample here.
It works on Chrome and FireFox. IE and Edge still does not support clip-path
That's an another way to do it using pure CSS:
HTML
<div class="circular--portrait">
<img src='http://i.imgur.com/22W12EQ.jpg'/>
</div>
CSS
.circular--portrait {
position: relative;
overflow: hidden;
width: 100px;
height: 100px;
border-radius: 50%;
}
.circular--portrait img {
width: 100%;
height: auto;
margin-top: -30px;
}
Code Snippet (with portrait and landscape examples)
Alright, took me a moment but this is what I came up with:
function ScaleImage(srcwidth, srcheight, targetwidth, targetheight, fLetterBox, xOffSet, yOffSet) {
var result = { width: 0, height: 0, fScaleToTargetWidth: true };
if ((srcwidth <= 0) || (srcheight <= 0) || (targetwidth <= 0) || (targetheight <= 0)) {
return result;
}
// scale to the target width
var scaleX1 = targetwidth;
var scaleY1 = (srcheight * targetwidth) / srcwidth;
// scale to the target height
var scaleX2 = (srcwidth * targetheight) / srcheight;
var scaleY2 = targetheight;
// now figure out which one we should use
var fScaleOnWidth = (scaleX2 > targetwidth);
if (fScaleOnWidth) {
fScaleOnWidth = fLetterBox;
}
else {
fScaleOnWidth = !fLetterBox;
}
if (fScaleOnWidth) {
result.width = Math.floor(scaleX1);
result.height = Math.floor(scaleY1);
result.fScaleToTargetWidth = true;
}
else {
result.width = Math.floor(scaleX2);
result.height = Math.floor(scaleY2);
result.fScaleToTargetWidth = false;
}
//result.targetleft = Math.floor((targetwidth - result.width) / 2);
//result.targettop = Math.floor((targetheight - result.height) / 2);
result.targetleft = Math.floor((targetwidth - result.width) / 2 - xOffSet);
result.targettop = Math.floor((targetheight - result.height) / 2 - yOffSet);
return result;
}
function OnImageLoad(evt, xOffSet = 0, yOffSet = 0) {
var img = evt.currentTarget;
// what's the size of this image and it's parent
var w = $(img).width();
var h = $(img).height();
var tw = $(img).parent().width();
var th = $(img).parent().height();
// compute the new size and offsets
var result = ScaleImage(w, h, tw, th, false, xOffSet, yOffSet);
// adjust the image coordinates and size
img.width = result.width;
img.height = result.height;
$(img).css("left", result.targetleft);
$(img).css("top", result.targettop);
}
.result {
width: 250px;
height: 250px;
border: thick solid #666666;
overflow: hidden;
position: relative;
border-radius: 50%;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
No offset:
<div class='result'>
<img src="http://i.imgur.com/22W12EQ.jpg" style="position: absolute;" onload="OnImageLoad(event, 0, 0);"/>
</div>
Y offset:
<div class='result'>
<img src="http://i.imgur.com/22W12EQ.jpg" style="position: absolute;" onload="OnImageLoad(event, 0, 30);"/>
</div>
I took most of the work from this resource: https://selbie.wordpress.com/2011/01/23/scale-crop-and-center-an-image-with-correct-aspect-ratio-in-html-and-javascript/ and I've adepted it to allow the use of Offsets so you can crop any image at the position you want.
How it works
You create a div of any size you want. It can be square, but if you want an egg-like result, that works as well (lol). Then insert the image of any unknown size inside it.
Change onload="OnImageLoad(event, 0, 30); with the offsets you want. Positive offsets for moving the image left or down, negative for up or right.
Note: I did use jQuery for this.
I'm trying to come up with an effective way of defining a nested flexbox and allow it to be resized. I think it's almost there:
http://jsfiddle.net/6j10L3x2/1/
I'm using three custom elements purely to make the mark-up more declarative:
flex, flex-item, flex-resizer
A flex represents the container. A flex-item presents an element within the container, and flex-resizer represents a resizer widget which can be placed between two flex-items to add resizing functionality between them.
This all appears to work really well. However, it only handles items sized with flex-grow. If flex-shrink or flex-basis is defined, then the calculations simply don't work.
Can anyone suggest a way to amend this to allow it work for all cases? I realise that there is some ambiguity in regards to how the space should be shared between items with various flex configurations, but any input would be welcome.
Any alternative approaches would be welcome also. Thanks.
Wow. I am impressed how you resize the flexbox elements with vanilla javascript using 'flexGrow', excelent idea and code.
I have improve your code in a few ways and it is working very well.
What I did?
1.- I simplified the HTML:
Do not use a flex element inside a flex-item.
Use a flex or flex-item element, always!, inside another
flex element.
2.- Solved!
Splitter's jump when the visible flex-item size is smaller that its content size.
3.- I'd added different cursors to signal a state's change (setupResizerEvents, onMouseUp) to improve usability.
4.- I've added code to prevent the cursor from flickering when dragging.
5.- use of offsetWidth and offsetHeight in manageResize() versus scrollWidth and scrollHeight to avoid splitter's jump on resize when a flex-item content overflow (overflow: auto).
Here is the code:
function manageResize(md, sizeProp, posProp) {
var r = md.target;
var prev = r.previousElementSibling;
var next = r.nextElementSibling;
if (!prev || !next) {
return;
}
md.preventDefault();
var prevSize = prev[sizeProp];
var nextSize = next[sizeProp];
var sumSize = prevSize + nextSize;
var prevGrow = Number(prev.style.flexGrow);
var nextGrow = Number(next.style.flexGrow);
var sumGrow = prevGrow + nextGrow;
var lastPos = md[posProp];
function onMouseMove(mm) {
var pos = mm[posProp];
var d = pos - lastPos;
prevSize += d;
nextSize -= d;
if (prevSize < 0) {
nextSize += prevSize;
pos -= prevSize;
prevSize = 0;
}
if (nextSize < 0) {
prevSize += nextSize;
pos += nextSize;
nextSize = 0;
}
var prevGrowNew = sumGrow * (prevSize / sumSize);
var nextGrowNew = sumGrow * (nextSize / sumSize);
prev.style.flexGrow = prevGrowNew;
next.style.flexGrow = nextGrowNew;
lastPos = pos;
}
function onMouseUp(mu) {
// Change cursor to signal a state's change: stop resizing.
const html = document.querySelector('html');
html.style.cursor = 'default';
if (posProp === 'pageX') {
r.style.cursor = 'ew-resize';
} else {
r.style.cursor = 'ns-resize';
}
window.removeEventListener("mousemove", onMouseMove);
window.removeEventListener("mouseup", onMouseUp);
}
window.addEventListener("mousemove", onMouseMove);
window.addEventListener("mouseup", onMouseUp);
}
function setupResizerEvents() {
document.body.addEventListener("mousedown", function (md) {
// Used to avoid cursor's flickering
const html = document.querySelector('html');
var target = md.target;
if (target.nodeType !== 1 || target.tagName !== "FLEX-RESIZER") {
return;
}
var parent = target.parentNode;
var h = parent.classList.contains("h");
var v = parent.classList.contains("v");
if (h && v) {
return;
} else if (h) {
// Change cursor to signal a state's change: begin resizing on H.
target.style.cursor = 'col-resize';
html.style.cursor = 'col-resize'; // avoid cursor's flickering
// use offsetWidth versus scrollWidth (and clientWidth) to avoid splitter's jump on resize when a flex-item content overflow (overflow: auto).
manageResize(md, "offsetWidth", "pageX");
} else if (v) {
// Change cursor to signal a state's change: begin resizing on V.
target.style.cursor = 'row-resize';
html.style.cursor = 'row-resize'; // avoid cursor's flickering
manageResize(md, "offsetHeight", "pageY");
}
});
}
setupResizerEvents();
body {
/* margin:0; */
border: 10px solid #aaa;
}
flex {
display: flex;
overflow: hidden;
}
/* flex-item > flex {
position: absolute;
width: 100%;
height: 100%;
} */
flex.h {
flex-direction: row;
}
flex.v {
flex-direction: column;
}
flex-item {
/* display: flex; */
/* position: relative; */
/* overflow: hidden; */
overflow: auto;
}
flex > flex-resizer {
flex: 0 0 10px;
/* background: white; */
background-color: #aaa;
background-repeat: no-repeat;
background-position: center;
}
flex.h > flex-resizer {
cursor: ew-resize;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='30'><path d='M2 0 v30 M5 0 v30 M8 0 v30' fill='none' stroke='black'/></svg>");
}
flex.v > flex-resizer {
cursor: ns-resize;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='30' height='10'><path d='M0 2 h30 M0 5 h30 M0 8 h30' fill='none' stroke='black'/></svg>");
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>flex-splitter</title>
<link rel="stylesheet" href="./src/styles.css">
<script src="./src/index.js" defer></script>
</head>
<body>
<flex class="v" style="flex: 1; height: 500px;">
<flex-item style="flex: 1;">Flex 1</flex-item>
<flex-resizer></flex-resizer>
<flex class="h" style="flex: 1;">
<flex-item style="flex: 1; background-color: aqua;">
<!--
The next section is an example to test the splitter when there is content inside a flex-item
-->
<section>
<div>
<label for="CursorCoor" style="display: block;">showCursorCoor: </label>
<textarea id="CursorCoor" rows="6" cols="50" wrap="soft" readonly></textarea>
</div>
<br />
<div>
<label for="boxInfo" style="display: block;">showBoxInfo: </label>
<textarea id="boxInfo" rows="6" cols="50" wrap="soft" readonly></textarea>
</div>
</section>
</flex-item>
<flex-resizer></flex-resizer>
<flex class="v" style="flex: 2; ">
<flex-item style="flex: 1; background: pink;">Flex 3</flex-item>
<flex-resizer></flex-resizer>
<flex class="h" style="flex: 1">
<flex-item style="flex: 1; background: green;">Flex 4</flex-item>
<flex-resizer></flex-resizer>
<flex-item style="flex: 2;">Flex 5</flex-item>
<!-- <flex-resizer></flex-resizer> -->
<flex-item style="flex: 3; background: darkorange;">Flex 6</flex-item>
</flex>
</flex>
</flex>
</flex>
</body>
</html>
Or see it on Codesandbox:
I hope it helps!
Note: There is also the new, basic resize CSS property, but it's only for bottom right corner dragging.
I did some research on this, and the first 3 framework-free, fully baked results I came across were, in order of appearances (untested):
https://daybrush.com/moveable
"Moveable is Draggable, Resizable, Scalable, Rotatable, Warpable, Pinchable, Groupable, Snappable"
I love the look of things here, both visually and code-wise! Seems highly functional and extremely flexible as well.
See also: https://github.com/daybrush/moveable https://daybrush.com/moveable/release/latest/doc
UPDATE: I tried this one out, I actually would not recommend it. It's very complicated to use, poorly documented, and I'd rather write my own JS instead.
https://split.js.org
Looks nice, but it appears to only be for split panels specifically, no e.g. corner dragging. If that's all you want, this might be a good option.
See also: https://github.com/nathancahill/split/tree/master/packages/splitjs https://github.com/nathancahill/split/tree/master/packages/split-grid
https://jspanel.de
Not as aesthetic as I would like, but seems like it has a good set of functionality and options.
See also: https://github.com/Flyer53/jsPanel4
I also found this: http://w2ui.com/web/home https://github.com/vitmalina/w2ui