I have a tab with heading. I want to make it editable when the user double click on it. So currently i hide the div with heading and replace it by adding a input element dynamically. When i add the input element dynamically the size of the header-wrapper div increases.
I want my dynamically added input take same size as that of the heading element(which is hidden now). And the size of the wrapper div should remain same. I have tried a solution with js. But i am looking a solution purely using CSS. Could this use case be achieved using css alone.
I want my header-wrapper to be fluid and not of fixed width. I just want my input to take same width as that of div with class head. Input should take same width and size as that of head width.
function dblClickHanlder(){
console.log("dbl click handler called");
let inputEl = document.createElement("input");
inputEl.style.display="inline-block";
let headEl = document.querySelector(".head");
headEl.style.display="none";
document.querySelector(".header-wrapper").appendChild(inputEl);
inputEl.focus();
}
* {
box-sizing: border-box;
}
.wrapper{
border: 1px solid black;
display:flex;
flex:1 0 auto;
}
.header-wrapper{
display: flex;
border: 1px solid red;
}
<div class="wrapper">
<div class="header-wrapper">
<div ondblclick="dblClickHanlder()" class="head">Heading</div>
</div>
</div>
you can get previous width and height of head element before removing it and set to newly created input;
inputEl.style.width = headEl.offsetWidth + "px";
inputEl.style.height = headEl.offsetHeight + "px";
check the snippet below:
function dblClickHanlder(){
console.log("dbl click handler called");
let headEl = document.querySelector(".head");
let inputEl = document.createElement("input");
inputEl.style.width = headEl.offsetWidth + "px";
inputEl.style.height = headEl.offsetHeight + "px";
headEl.style.display="none";
document.querySelector(".header-wrapper").appendChild(inputEl);
inputEl.focus();
}
* {
box-sizing: border-box;
}
.wrapper{
border: 1px solid black;
display:flex;
flex:1 0 auto;
}
.header-wrapper{
display: flex;
border: 1px solid red;
}
<div class="wrapper">
<div class="header-wrapper">
<div ondblclick="dblClickHanlder()" class="head">Heading</div>
</div>
</div>
Just add the following class to your CSS:
.header-wrapper input {
max-width: 50px;
}
Below is the working example:
function dblClickHanlder() {
console.log("dbl click handler called");
let inputEl = document.createElement("input");
inputEl.style.display = "inline-block";
let headEl = document.querySelector(".head");
headEl.style.display = "none";
document.querySelector(".header-wrapper").appendChild(inputEl);
inputEl.focus();
}
* {
box-sizing: border-box;
}
.wrapper {
border: 1px solid black;
display: flex;
flex: 1 0 auto;
}
.header-wrapper {
display: flex;
border: 1px solid red;
}
.header-wrapper input {
max-width: 50px;
}
<div class="wrapper">
<div class="header-wrapper">
<div ondblclick="dblClickHanlder()" class="head">Heading</div>
</div>
</div>
Related
I have a grid that draws squares in cells. It has number of rows and number of columns, then it draw the grid cells and check if in each cell there should be a square or not (according to an array) and draws a square if needed.
The HTML end result looks something like this: (lets say I have 1 row and 3 columns and only 2 cells should have squars)
.row {
display: flex;
flex-wrap: wrap;
flex: 10000 1 0%;
}
.column {
display: flex;
flex-wrap: wrap;
max-width: 100px;
min-width: 10px;
padding: 4px;
border: 1px solid grey;
}
.square {
background-color: red;
width: 100%;
aspect-ratio: 1/1;
border-radius: 5px;
}
<div class="row">
<div class="column">
<div class="square"></div>
</div>
<div class="column">
<div class="square"></div>
</div>
<div class="column"></div>
</div>
The rows take the full width of the screen and the size of the columns should be identical between all of the columns and changing by the number of columns on the screen (For example if I have 5 columns they should all be with a width of 100px, but if I have 1000 columns they should all be with a width of 10px).
My problem is that after a certain break point in the column size the padding and border radius seems weird and I want to change their values when I hit that break point.
I can't use #container queries as there are still not fully supported.
If it help I'm using vue 2. but I think a CSS solution will be better in this case.
Trying to address the issue described:
My problem is that after a certain break point in the column size the
padding and border radius seems weird and I want to change their
values when I hit that break point. I can't use #container queries as
there are still not fully supported.
I crafted a little demo that helped me better explore the conditions bringing to such a scenario.
Obtaining border: collapse equivalent on flexbox items
The .row element remains a flexbox container but its flex items instead of having their border set, they are styled with their outline set.
The outline doesn't occupy space and it's expected to "collapse" when colliding with the outline produced by another element.
So to make it sure the layout wasn't affected by styling oddities, in the attempt to show off the borders of the flex items, this demo just relies on 2 key aspects to render those borders:
Setting the gap between the flex items
Setting the outline size expected to cover the gap left between
elements
.row {
gap: var(--col-gap);
}
.column {
outline: var(--col-gap) solid gray;
}
Using ::after for adding content to an element
Plus the red dot is applied as an ::after pseudo element with position:absolute, again to make sure that nothing affected the grid layout:
.column.square::after {
position: absolute;
content: '';
background-color: red;
width: 50%;
aspect-ratio: 1/1;
border-radius: 100%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
The dashboard - exploring the options
Starting from there I added a "dashboard" with position: fixed that remains on top of the page and lets you control:
column width (px): here you set the width changing the cols per row according to the available container space
columns per row: here you set the cols per row changing their width according to the available container space
width
gap between cells (px): the gap between cells on the grid
toggle red dots visibility: will show/hide the red dots proving again that display: none; doesn't change the grid layout that it's depending exclusively by the .column element size set through the custom variable --col-width
toggle counter visibility: will show/hide the counter on top of each flex item
Conclusions so far:
Despite the efforts to minimize any interfence and taking all the steps needed to correctly setup a grid layout depending only on the fixed size of its cells, there are still some rendering issue with sometimes the occurrence of regular mismatching patterns on the border size for some lines. I should say that I only experience the problem on my laptop display and not on my desktop monitor so that's another factor.
I tried with different parameters on my demo and playing with the numbers, considering also the gap. A good and safe layout can be found minimizing potential problems (also raising the border size for example).
I couldn't get further than this using the flex layout.
const container = document.getElementById('container');
//draws the board
emptyElementAndFillWithColumns(container, 100);
//sets some columns randomly as .square
addRandomSquares(container);
//initializes the dashboard with the value coming from the css custom props
let columnsGap = parseInt(getCssCustomProp('col-gap'));
let columnsWidth = parseInt(getCssCustomProp('col-width'));
document.getElementById('gap').value = columnsGap;
document.getElementById('width').value = columnsWidth;
document.getElementById('width').dispatchEvent(new Event('change'));
document.getElementById('cols').value = Math.trunc(container.offsetWidth / (columnsWidth+columnsGap));
//input#width change event handler
document.getElementById('width')
.addEventListener('change', event => {
const width = parseInt(event.target.value);
const newCols = Math.trunc(container.offsetWidth / (width+columnsGap));
setCssCustomProp(container, 'col-width', `${width}px`);
document.getElementById('cols').value = newCols;
});
//input#cols change event handler
document.getElementById('cols')
.addEventListener('change', event => {
const cols = parseInt(event.target.value);
const newWidth = Math.trunc(container.offsetWidth / cols) - columnsGap;
setCssCustomProp(container, 'col-width', `${newWidth}px`);
document.getElementById('width').value = newWidth;
});
//input#gap change event handler
document.getElementById('gap')
.addEventListener('change', event => {
const gap = parseInt(event.target.value);
setCssCustomProp(container, 'col-gap', `${gap}px`);
columnsGap = gap;
});
//input#toggle-dots change event handler
document.getElementById('toggle-dots')
.addEventListener('change', event => {
container.classList.toggle('hide-dots');
});
//input#toggle-counters change event handler
document.getElementById('toggle-counters')
.addEventListener('change', event => {
container.classList.toggle('hide-counters');
});
//sets the --propName custom property at the style of target
function setCssCustomProp(target, propName, value){
target.style.setProperty(`--${propName}`, `${value}`);
}
//gets the --propName custom property value from the rule set on :root
function getCssCustomProp(propName){
const propValue =
getComputedStyle(document.documentElement).getPropertyValue(`--${propName}`);
return propValue;
}
//resets the container and appends a count number of columns
function emptyElementAndFillWithColumns(target, count){
for (i = 0; i <= count; i++) {
const column = document.createElement('div');
column.classList.add('column');
target.append(column);
}
}
//adds the square class to random .column elements in target
function addRandomSquares(target){
target.querySelectorAll('.column').forEach(column => {
if (Math.random() >= 0.5)
column.classList.add('square');
})
}
:root {
--col-width: 100px;
--col-gap: 1px;
}
*,
*::after,
*::before {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: sans-serif;
}
.row {
display: flex;
flex-wrap: wrap;
gap: var(--col-gap);
counter-reset: itemnr;
}
.column {
position: relative;
display: flex;
flex-wrap: wrap;
width: var(--col-width);
height: var(--col-width);
padding: 4px;
outline: var(--col-gap) solid gray;
}
.column.square::after {
position: absolute;
content: '';
background-color: red;
width: 50%;
aspect-ratio: 1/1;
border-radius: 100%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.dashboard {
position: fixed;
right: 1rem;
top: 2rem;
border: solid darkgray;
padding: 1em;
z-index: 100;
background: gray;
color: white;
font-weight: 600;
font-size: 1.2rem;
opacity: .9;
}
.dashboard > *{
display: grid;
grid-template-columns: 1fr auto;
width: 100%;
gap: 1em;
}
.dashboard label{
}
.dashboard input[type="number"] {
width: 5em;
cursor: pointer;
}
.dashboard input[type="checkbox"] {
width: 1rem;
line-height: 1rem;
cursor: pointer;
}
#container.hide-dots .square::after{
display: none;
}
#container.hide-counters .column::before{
display: none;
}
small{
grid-column: 1 / -1;
font-size:.8rem;
text-align: center;
width: 100%;
margin-bottom: 1rem;
}
.column::before{
position: absolute;
counter-increment: itemnr;
content: counter(itemnr);
font-size: .8rem;
z-index: 10;
font-weight: 600;
}
<div id="container" class="row">
<div class="column square">
</div>
<div class="column"></div>
</div>
<div class="dashboard">
<div>
<label for="width">column width (px):</label>
<input
id="width" type="number" max="100" min="10">
</div>
<div>
<label for="cols">columns per row:</label>
<input
id="cols" type="number" max="50" min="1">
</div>
<div>
<label for="gap">gap between cells (px):</label>
<input
id="gap" type="number" max="10" min="0">
</div>
<div style="margin-top: 1rem;">
<label for="toggle-dots">toggle red dots visibility:</label>
<input id="toggle-dots" type="checkbox" checked>
</div>
<div>
<label for="toggle-counters">toggle counter visibility:</label>
<input id="toggle-counters" type="checkbox" checked>
</div>
</div>
If you want to increase or decrease size of padding you can give padding size in percent (%) that depends on parent element.
When I run the example (in full page view) in Chrome (98) (or Safari 15.3) the first element directly vanishes when scrolling just a little bit, so kind of 'when leaving the non-padding or entering the padding-area'
The options define a rootMargin: '0px 0px 0px 0px' which I thought refer to the root elements border. That's how it behaves in Firefox(97). The inner element is only hidden when it reaches the top.
Is there a way to define the wrapper borders as boundary and not the 'inner padding-border'?
const wrapper = document.querySelector('#wrapper')
const firstElem = document.querySelector('#first-elem')
const options = {
root: wrapper,
rootMargin: '0px 0px 0px 0px',
threshold: 1
}
const observer = new IntersectionObserver(handleFade, options);
observer.observe(firstElem)
function handleFade(entries) {
entries.forEach(entry => {
let target = entry.target
if (entry.isIntersecting) {
target.classList.remove('fade-out')
} else {
target.classList.add('fade-out')
}
})
}
body {
padding: 0;
overflow: hidden;
}
#wrapper {
height: 100vh;
padding-top: 10rem;
overflow: auto;
border: 1px solid darkmagenta;
box-sizing: border-box;
}
.elem {
border: 3px solid teal;
padding: 0 2rem;
height: 20rem;
}
.fade-out {
visibility: hidden;
}
<div id="wrapper">
<div class="elem" id="first-elem">first watched element</div>
<div class="elem">element</div>
<div class="elem">element</div>
<div class="elem">element</div>
</div>
That's right. This might be a bit confusing but it seems to be the expected behavior according to the specs.
When you set a root for an IntersectionObserver instance, the so-called intersection rectangle — the area that the intersection is checked against — will be the content area of the root element.
The content area refers to the innermost area of an element, which excludes all the paddings:
As for the solution to this problem, you could simply have an extra wrapper element that you set the paddings on, and you remove any paddings from the root element:
const wrapper = document.querySelector('#wrapper');
const firstElem = document.querySelector('#first-elem');
const observer = new IntersectionObserver(entries => {
entries[0].target.classList.toggle('fade-out', !entries[0].isIntersecting)
}, {
root: wrapper,
threshold: 1,
});
observer.observe(firstElem)
body {
padding: 0;
margin: 0;
overflow: hidden;
}
#wrapper {
height: 100vh;
overflow: auto;
box-sizing: border-box;
}
#content {
border: 1px solid darkmagenta;
padding: 20px;
padding-top: 10rem;
}
.elem {
background-color: #eee;
border: 2px solid blue;
padding: 20px 30px;
height: 100px;
margin-bottom: 20px;
}
.fade-out {
visibility: hidden;
}
<div id="wrapper">
<div id="content">
<div class="elem" id="first-elem">first watched element</div>
<div class="elem">element</div>
<div class="elem">element</div>
<div class="elem">element</div>
<div class="elem">element</div>
<div class="elem">element</div>
<div class="elem">element</div>
<div class="elem">element</div>
</div>
</div>
Although your example is a bit strange, in the sense that I'm not sure what you were wanting to do, but regardless, any time you want to neutralize the effect of the paddings on the root but still have paddings around your content, the solution is to declare the paddings on an extra wrapper element.
Given that the scrolled wrapper element takes up the full height of the page, a different solution would be to simply remove root: wrapper from the options, so the elements position is watched in relation to the viewport
const wrapper = document.querySelector('#wrapper')
const firstElem = document.querySelector('#first-elem')
const options = {
rootMargin: '0px 0px 0px 0px',
threshold: 1
}
const observer = new IntersectionObserver(handleFade, options);
observer.observe(firstElem)
function handleFade(entries) {
entries.forEach(entry => {
let target = entry.target
if (entry.isIntersecting) {
target.classList.remove('fade-out')
} else {
target.classList.add('fade-out')
}
})
}
body {
padding: 0;
overflow: hidden;
}
#wrapper {
height: 100vh;
padding-top: 10rem;
overflow: auto;
border: 1px solid darkmagenta;
box-sizing: border-box;
}
.elem {
border: 3px solid teal;
padding: 0 2rem;
height: 20rem;
}
.fade-out {
visibility: hidden;
}
<div id="wrapper">
<div class="elem" id="first-elem">first watched element</div>
<div class="elem">element</div>
<div class="elem">element</div>
<div class="elem">element</div>
</div>
I have a case where users input text into a contenteditable div and the result is later displayed in a normal div. The input div has a max-width set to allow text to wrap to new lines.
The issue is that the text is displayed differently in the input vs the output. The input seems to break inside of words whereas the output lets the text overflow and only breaks in whitespace. Is it possible to get the same behavior in the input?
See this fiddle for an example: https://jsfiddle.net/s1m40m2p/1/
html
<body>
<div contenteditable="true" id="input-div" class="both-divs"></div>
<div id="output-div" class="both-divs"></div>
</body>
css
.both-divs {
min-height : 20px;
max-width: 100px;
font-size: 16px;
font-family: monospace;
overflow: visible;
}
#input-div {
outline: 1px solid red;
}
#output-div {
outline: 1px solid blue;
}
js
const inputElt = document.getElementById('input-div')
const outputElt = document.getElementById('output-div')
inputElt.addEventListener('input', () => {
outputElt.innerText = inputElt.innerText;
})
output
try and add overflow-wrap:normal in #input-div {` your problem will be solved
const inputElt = document.getElementById('input-div')
const outputElt = document.getElementById('output-div')
inputElt.addEventListener('input', () => {
outputElt.innerText = inputElt.innerText;
})
.both-divs {
min-height : 20px;
max-width: 100px;
font-size: 16px;
font-family: monospace;
overflow: visible;
}
#input-div {
outline: 1px solid red;
overflow-wrap:normal;
}
#output-div {
outline: 1px solid blue;
}
<html>
<body>
<div contenteditable="true" id="input-div" class="both-divs">
</div>
<div id="output-div" class="both-divs">
</div>
</body>
</html>
I have an iframe border using CSS. As the page is resized the border sometimes disappears in Chrome and changes size in Safari (it's fine in Firefox)
Is there a known workaround?
const html = `
<style>
body {
background: #DDD;
}
</style>
<body>
<div>hello iframe</div>
</body>
`;
const blob = new Blob([html], {type: 'text/html'});
document.querySelector("iframe").src = URL.createObjectURL(blob);
div {
max-width: 90%;
margin: 0 auto;
}
iframe {
display: block;
border: 1px solid black;
width: 100%;
background: red;
}
<p>Size the window and watch the right border</p>
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
<iframe></iframe>
</div>
Using other elements don't have the same issue
div {
max-width: 90%;
margin: 1em auto;
}
span, canvas {
display: block;
border: 1px solid black;
width: 100%;
height: 60px;
background: #eee;
}
<p>no issue with other elements</p>
<div>
<span></span>
</div>
<div>
<canvas></canvas>
</div>
note that it seems to have something to do with having a background color in the iframe. If I remove the background color the problem goes away in Chrome (though not Safari)
const html = `
<body>
<div>hello iframe</div>
</body>
`;
const blob = new Blob([html], {type: 'text/html'});
document.querySelector("iframe").src = URL.createObjectURL(blob);
div {
max-width: 90%;
margin: 0 auto;
}
iframe {
display: block;
border: 1px solid black;
width: 100%;
}
<p>Size the window and watch the right border</p>
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
<iframe></iframe>
</div>
Adding a wrapper div with overflow: hidden; and box-sizing: border-box; works for me.
const html = `
<style>
body {
background: #eee;
}
</style>
<body>
<div>hello iframe</div>
</body>
`;
const blob = new Blob([html], {type: 'text/html'});
document.querySelector("iframe").src = URL.createObjectURL(blob);
div {
max-width: 90%;
margin: 0 auto;
}
.iframe-wrapper {
border: 1px solid black;
box-sizing: border-box;
width: 100%;
overflow: hidden;
}
iframe {
display: block;
width: 100%;
border: none;
}
<p>Size the window and watch the right border</p>
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
<div class="iframe-wrapper">
<iframe></iframe>
</div>
</div>
I still see the issue on Chrome (not on Safari). It seems like a bug in visualization of the border (still).
One option could be to change the border to have a width of 0 and set an outline instead. Then this effect goes away. I don't know if it would be the best solution (outlines are used often to highlight focused/active elements), but it would be close to what you have.
Here is a demo just with that change:
const html = `
<style>
body {
background: #eee;
}
</style>
<body>
<div>hello iframe</div>
</body>
`;
const blob = new Blob([html], {type: 'text/html'});
document.querySelector("iframe").src = URL.createObjectURL(blob);
div {
max-width: 90%;
margin: 0 auto;
}
iframe {
display: block;
border: 0;
outline: 1px solid black;
width: 100%;
}
<p>Size the window and watch the right border</p>
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
<iframe></iframe>
</div>
This is an antialiasing issue.
Chrome generally avoids rendering on floating pixels, to avoid antialiasing. It will try to move and resize to the next rounded pixels.
In this case, it will cut off your border instead of making it leak outside of the iframe.
You can force it by either moving or resizing your iframe by floating-pixels:
const html = `
<style>
body {
background: #DDD;
}
</style>
<body>
<div>hello iframe</div>
</body>
`;
const iframe = document.querySelector("iframe");
iframe.srcdoc = html;
document.querySelector("input").oninput = function(e) {
iframe.style.marginLeft = this.value + 'px';
};
div {
max-width: 90%;
margin: 0 auto;
}
iframe {
display: block;
border: 1px solid black;
width: 250.5px; /* force a floating pixel width */
background: red;
}
<p>Edit the range and watch the right border</p>
<input type="range" min="0" max="1" value="0" step="0.01">
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
<iframe></iframe>
</div>
I think you did good opening this issue, since it's definitely not the expected behavior.
And since you asked for a workaround, here is one, far from being perfect, which will cause double reflows at each resize event, but which should fix the bug...
const html = `
<style>
body {
background: #DDD;
}
</style>
<body>
<div>hello iframe</div>
</body>
`;
const iframe = document.querySelector("iframe");
iframe.srcdoc = html;
addEventListener('resize', resizeFrame, {passive: true});
resizeFrame();
function resizeFrame(_){
iframe.style.width = null; // reset to 100%
// force reflow by calling offsetWidth which is already rounded
iframe.style.width = iframe.offsetWidth + 'px';
}
div {
max-width: 90%;
margin: 0 auto;
}
iframe {
display: block;
border: 1px solid black;
width: 100%;
background: red;
}
<p>Size the window and watch the right border</p>
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
<iframe></iframe>
</div>
But note that this code only takes care of resize events, if your iframe can resize from other events (e.g DOM manips, CSS etc.) then you might want to use a wrapper element on which you'd apply the width:100% and from a ResizeObserver's callback change your iframe's width:
const html = `
<style>
body {
background: #DDD;
}
</style>
<body>
<div>hello iframe</div>
</body>
`;
const iframe = document.querySelector("iframe");
iframe.srcdoc = html;
if(window.ResizeObserver) {
const observer = new ResizeObserver(entries => {
iframe.style.width = iframe.parentNode.offsetWidth + 'px';
});
observer.observe(iframe.parentNode);
}
else {
console.log('no support');
}
div {
max-width: 90%;
margin: 0 auto;
}
iframe {
display: block;
border: 1px solid black;
width: 100%;
background: red;
}
.iframe-wrapper {
max-width: none;
width: 100%;
}
<p>Size the window and watch the right border</p>
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
<div class="iframe-wrapper">
<iframe></iframe>
</div>
</div>
That is, in Blink only for now...
For anyone looking for an answer to this in 2022 and none of the above works, this is the only thing that worked for me.
Add the following CSS to the iframe:
clip-path: polygon(1% 1%, 99% 1%, 99% 99%, 1% 99%);
.ifrmoutr{
border: 1px solid red;
width:100%;
overflow:hidden;
}
.ifrmoutr iframe{
width:100%;
}
<div class="row">
<div class="col-lg-12">
<div class="ifrmoutr">
<iframe></iframe>
</div>
</div>
</div>
i wonder how it is possible to have multiple spans inside a div, with the last span floating to the bottom right and taking all the remaining width in the "row".
Here is a fiddle: http://jsfiddle.net/gpakL/
The problem is, that the fullWidth span is not always at the bottom. You can resize your browser window to see the fullWidth span moving.
This is how it should look like:
This is how it shold not look like:
HTML:
<div class="container">
<span class="item">sdfdsfsdf</span>
<span class="item">sdfsdfsdfsdf</span>
<span class="item">dsfdsfdsfsd</span>
<span class="item">fsdfsdfsdffsdf</span>
<span class="item">dsgsdf</span>
<span class="item">dfd</span>
<span class="item">fdfdf</span>
<span class="itemFullWidth">FullWidth</span>
</div>
CSS:
.container {
background-color: blue;
width: 50%;
}
.item {
float: left;
background-color: orange;
height: 30px;
line-height: 30px; /* Vertically center */
margin: 5px;
}
.itemFullWidth {
background-color:green;
display: block;
overflow: hidden;
height: 30px;
line-height: 30px; /* Vertically center */
margin: 5px;
min-width: 80px;
}
If you open to use flexbox, it could be easily done (WebKit demo):
.container {
display: flex;
flex-wrap: wrap; /* allow multiple rows */
}
.container > :last-child {
flex: 1; /* absorb remaining space */
}
check this,
Using position: relative; for the container and position: absolute; for the
.itemFullWidth, you can get it to work to some extent. You'll need some js I guess.
You could consider a JavaScript/jQuery assisted solution for this problem. In a more general case, there are jQuery packages like David DeSandro's Masonry or Packery or Isotope: http://desandro.com/
Here is my version of how you could do this using jQuery.
function resetEndItemWidth() {
var wContainer = $(".container").width();
var minWidthEndItem = parseInt($(".itemFullWidth").css("min-width"));
var endItemMargins = $(".itemFullWidth").outerWidth(true)
- $(".itemFullWidth").outerWidth();
var prevItemOffset = $(".itemFullWidth").prev().offset();
var prevItemWidth = $(".itemFullWidth").prev().outerWidth(true);
var freeWidth = wContainer - (prevItemWidth + prevItemOffset.left);
if (freeWidth < minWidthEndItem) {
newWidth = wContainer - endItemMargins;
} else {
newWidth = Math.max(minWidthEndItem,freeWidth);
}
$(".itemFullWidth").width(newWidth);
}
resetEndItemWidth();
$(window).resize(function(){resetEndItemWidth();});
See the demo at: http://jsfiddle.net/audetwebdesign/m6bx8/
How This Works
I look at the floated sibling before the last item (.itemFullWidth) and determine the amount of free space remaining on the line.
If there is enough free space, I reset the width of the full width item to fill the gap,
otherwise, the full width item is on a separate line and I set it to the width of the parent container.
For full width item (.endItemMargins), you need to account for the left-right margins and you need to get the minimum width from the min-width property.
The min-width requirement could be relaxed if you initialize the original with of the full width item.
Other Comments
The flex box solution is much more elegant. However, it is good to have some options.
Simple jQuery solution, however CSS solutions should be preferred over JS solutions.
http://jsfiddle.net/A8mSu/
HTML:
<div class="container clearfix">
<span class="item">sdfdsfsdf</span>
<span class="item">sdfsdfsdfsdf</span>
<span class="item">dsfdsfdsfsd</span>
<span class="item">fsdfsdfsdffsdf</span>
<span class="item">dsgsdf</span>
<span class="item">dfd</span>
<span class="item">fdfdf</span>
<span class="item itemFullWidth">FullWidth</span>
</div>
JS:
function setWidth()
{
$obj = $('.container .itemFullWidth');
$obj.width('auto').width($obj.parent().width() - $obj.position().left);
}
$(window).resize(setWidth);
$(document).ready(setWidth);
CSS:
.container {
background-color: blue;
width: 50%;
}
.item {
float: left;
background-color: orange;
height: 30px;
line-height: 30px; /* Vertically center */
margin: 5px;
}
.itemFullWidth {
background-color: green;
min-width: 80px;
margin-right: 0;
}
.clearfix:after {
content:"";
display: table;
clear: both;
}
try , Please Checkout http://jsfiddle.net/gpakL/14/
function findWidth (){
var ConWidth = $('.container').width();
var leftWidth = $('.container .item:last').offset().left
var lastItemWidth = $('.container .item:last').width();
var fixPos = ConWidth - (leftWidth + lastItemWidth)
$('.container .itemFullWidth').width( fixPos -20 );
};
$(document).ready(function(){
findWidth();
});
$(window).resize(function(){
findWidth();
});