I have a layout problem and I'm having trouble thinking of a solution.
This is part of a form and basically its a dynamic list of checkboxes and their labels. Based on the screen width its either in 1, 2, or 3 columns.
We're arranging in columns, like for 3 columns:
1 5 9
2 6 10
3 7
4 8
If they were static this would be easy to do with css columns... but the challenge is that these are part of a treeview where each item can expand to show more items:
With CSS columns (or flexbox columns with a set height) if you expand, say, "2017" it will push the dates below it into the next column which I believe would be confusing for the end user. So ideally when 2017 is expanded, it would push everything below it down instead of into the next column.
This can be almost achieved by using flexbox and flex-wrap... but the only issue is the order.
So I basically want flexbox rows functionality with ordering like columns. I'm not great at math so I was wondering if there's something that can be done purely with CSS... but otherwise I am open to javascript solutions as well, though it needs to be accessible.
And ideas?
Thanks.
I figured out a solution using CSS grids, grid-auto-flow: column;, and using Javascript to count the items I need to layout and inject it into some CSS into the document.
function injectStyles(rule) {
var reviewCount = document.querySelector("#tree-case-review-date .fancytree-container").childElementCount;
var reviewCountTwo = Math.ceil(reviewCount / 2);
var reviewCountThree = Math.ceil(reviewCount / 3);
var purCount = document.querySelector("#tree-pur .fancytree-container").childElementCount;
var purCountTwo = Math.ceil(purCount / 2);
var purCountThree = Math.ceil(purCount / 3);
var div = $("<div />", {
html: '<style>#media only screen and (min-width:700px) { #tree-case-review-date .fancytree-container { grid-template-rows: repeat(' + reviewCountTwo + ', auto);} #tree-pur .fancytree-container { grid-template-rows: repeat(' + purCountTwo + ', auto);}}#media only screen and (min-width:1000px) { #tree-case-review-date .fancytree-container { grid-template-rows: repeat(' + reviewCountThree + ', auto);}#tree-pur .fancytree-container {grid-template-rows: repeat(' + purCountThree + ', auto);}}</style>'
}).appendTo("body");
}
window.onload = function() {
injectStyles();
};
I think this is an ungodly mismash of jquery and normal javascript, so I need to learn how to clean this up.
Related
I try to manage separators (like a "-") between each element of a list.
It's relatively simple when we only have one line, but I can't do it with more than one line.
When the site is displayed on a big screen I have:
Example center aligned
Listitem1 - listitem2 - listitem3 - ... - listitemX
The last item having no separator "-"
html
<p>
<a>listitem1</a>
<a>listitem2</a>
<a>listitem3</a>
<a>listitem4</a>
<a>listitem5</a>
<a>listitem6</a>
<a>listitem7</a>
...
<a>listitemX</a>
</p>
CSS
a:nth-child(n+2)::before {
content: " - "
}
This is relatively easy in CSS using :: before from the 2nd child...
But with media queries, when my screen shrinks and this same list spans multiple lines, I would like to remove the last "-" separator from each line.
Example center aligned
Listitem1 - listitem2 - listitem3 - listitem4 (without the separator here)
Listitem5 - listitem6 - listitem6 - listitem8 (without separator here either)
Listitem9 - etc ...
Does anyone have an idea?
Thank you in advance. Sebastian
There doesn’t seem to be a pure CSS solution, but you can use a bit of JS to set or unset a class based on whether an item is the first in a line.
Here I’m setting the text color to transparent rather than the content to "" because changing the content affects width, which then jumps around as it wraps/resizes.
a.firstInLine::before {
color: transparent;
}
The Javascript goes through the nodes and checks whether it’s lower on the page than the previous node. If it is (by more than a small margin of error), it sets the class firstInLine:
function calcY() {
document.querySelectorAll("p a").forEach((n, i, nodes) => {
if(i > 0) {
const thisY = n.getClientRects()[0].y;
const prevY = nodes[i - 1].getClientRects()[0].y;
if(thisY - prevY > 4) {
n.classList.add("firstInLine");
}
else {
n.classList.remove("firstInLine");
}
}
});
}
window.addEventListener("resize", calcY);
calcY();
I should add that there are a couple of other CSS things to set. We don’t want it to wrap, and in order for getClientRects to work right, it can’t be a purely inline element, so:
a {
white-space: nowrap;
display: inline-block;
}
CodePen
This question already has answers here:
Changing the browser zoom level
(10 answers)
Closed 4 years ago.
This post was edited and submitted for review 1 year ago and failed to reopen the post:
Duplicate This question has been answered, is not unique, and doesn’t differentiate itself from another question.
I want to change scale of visualViewport. I want to control zoom pragmatically on certain condition. How can I achieve this?
Edit: The window.visualViewport.scale is totally different from the zoom of the CSS transforms which was previously referred as a solution to this problem and as a reason for locking this question. CSS transforms operate inside the layout viewport while visualViewport scale does not affect the layout per design.
This i believe from what I've researched and read will need an API.
I have found some code on the subject and a link to where you can understand how this API works. I think if I understand your question, this will be a solution:
let pendingUpdate = false;
function viewportHandler() {
if (pendingUpdate) return;
pendingUpdate = true;
requestAnimationFrame(() => {
pendingUpdate = false;
var layoutViewport = document.getElementById('layoutViewport');
// Since the bar is position: fixed we need to offset it by the
// visual viewport's offset from the layout viewport origin.
var offsetLeft = viewport.offsetLeft;
var offsetTop = viewport.height
- layoutViewport.getBoundingClientRect().height
+ viewport.offsetTop;
// You could also do this by setting style.left and style.top if you
// use width: 100% instead.
bottomBar.style.transform = 'translate(' +
offsetLeft + 'px,' +
offsetTop + 'px) ' +
'scale(' + 1/viewport.scale + ')'
}
}
window.visualViewport.addEventListener('scroll', viewportHandler);
window.visualViewport.addEventListener('resize', viewportHandler);
Check it out: https://developer.mozilla.org/en-US/docs/Web/API/Visual_Viewport_API
I've a rather complicated website design I'm working on. I have the following 4 containers (I call them that, but they don't have the .container class)
In a wide screen layout:
In a narrow screen layout:
The issue I'm having is matching the total height of the white, grey and yellow containers with the blue container on a wide screen layout:
The grey and yellow containers are in a .row div, so adding the style { display: inline-flex } makes them the same height on a narrow screen layout:
However, this moves them completely to the side in the wide screen layout and this wouldn't match the combined white, grey and yellow containers with the blue container:
I tried a JavaScript solution as #Paulie_D recommended.
$(window).load(function () {
NormalizeHeights();
});
window.onresize = function (event) {
NormalizeHeights();
}
function NormalizeHeights() {
if (window.innerWidth >= 768) {
var carousel = $(".carousel-container");
var dashTop = $(".dash-row-top");
var panelLeft = $(".dash-row-bottom .panel-lightgray");
var panelRight = $(".dash-row-bottom .panel-yellow");
var carouselHeight = parseFloat(carousel.css('height'));
var dashTopHeight = parseFloat(dashTop.css('height'));
var panelLeftHeight = parseFloat(panelLeft.css('height'));
var panelRightHeight = parseFloat(panelRight.css('height'));
var dashBottomHeight;
if (panelLeftHeight > panelRightHeight) {
dashBottomHeight = panelLeftHeight;
}
else {
dashBottomHeight = panelRightHeight;
}
if (carouselHeight > (dashTopHeight + dashBottomHeight)) {
var difference = carouselHeight - (dashTopHeight + dashBottomHeight);
panelLeft.css("height", (dashBottomHeight + difference));
panelRight.css("height", (dashBottomHeight + difference));
}
else {
var difference = (dashTopHeight + dashBottomHeight) - carouselHeight;
carousel.css("height", (carouselHeight + difference));
panelLeft.css("height", (dashBottomHeight));
panelRight.css("height", (dashBottomHeight));
}
}
}
This works, sort off, but it's extremely unlikable in my estimation.
I had a similar problem and the solution I found was rather ugly but worked for me.
I used divs that would clear formats BUT would their presence would be conditioned (using ng-if). Programmatically, I measured the width of the screen and set a threshold. If the width was above the threshold, I set the location of the divs, measured the height of the contents and, when applicable, forcefully changed the height of all the relevant divs to look the same (note that you would need to set this size update AFTER A TIMER is fired to let the rendering to complete).
Hope this gives you some ideas and remember: I was the first to call this ugly.
Is there a way to autosize HTML table height based on content? Also if it's a cell (or cells) next to a neighbor cell with multiple rowspans.
E.g. if I have a table like this (cell on the right has Rowspan="2" and height of the cell content = 600px, in each cell on the left height of the cell content = 150px):
there is a gap between 2 cell consents on the left because cells themselves autosized their height. I'd like it to look like this:
Where top cells automatically collapse to cell content height. Is there anyway to achieve this?
This sets the last row of cells to the correct height (demo):
function grow(td) {
var table, target, high, low, mid;
td = $(td);
table = td.closest('table');
target = table.height();
low = td.height();
// find initial high
high = low;
while (table.height() <= target) {
td.height(high *= 2);
}
// binary search!
while (low + 1 < high) {
mid = low + Math.floor((high - low) / 2);
td.height(mid);
if (table.height() > target) {
high = mid;
} else {
low = mid;
}
}
td.height(low);
}
$('tr:last-child td').each(function() { grow(this); });
It should be trivial to convert this into plain JavaScript.
Update: For more complicated tables, you'll want to replace the last line with this (demo):
$.each($('td').get().reverse(), function() { grow(this); });
The idea is to call grow() on every cell, starting with the last row and working upwards.
considering table id="mytable" it would be:
$("#mytable").find("td").each(function(){
var ContentHeight = $($(this).html()).height();
$(this).height(ContentHeight);
});
at the end of the your page create a javascript code and let it do it for you:
<script type="text/javascript">
document.getElementById("idOfTd").style.height="100px";
</script>
I think it better create like this http://jsfiddle.net/miqdad/w9QYB/
I have this html:
<div id="subNav"></div>
<div id="feed"></div>
<div id="feedBar"></div>
I have floated all of these divs left. I set the width of #subNav and #feedBar, but on #feed I set its min-width . It takes the min-width even though the window is larger. Is there any way that with floating you can make the min-width work? I am trying to make a flexible layout on the page.
The following answer uses a JavaScript solution, in response to #Chromedude's comment (to the original question):
#David Is there any way to override this behavior? with javascript?
I'm sure there's a far more simple way of doing this (certainly with a JavaScript library), but this was the best I could come up with at this time of morning (in the UK):
var feed = document.getElementById('feed');
var width = document.width;
var feedBarWidth = document.getElementById('feedBar').clientWidth;
var subNavWidth = document.getElementById('subNav').clientWidth;
feed.setAttribute('style', 'width: ' + (width - (subNavWidth + feedBarWidth)) + 'px');
JS Fiddle demo.
Using jQuery (just as a suggestion as to the ease offered by a library):
var bodyWidth = $(document).width();
var subNavWidth = $('#subNav').width();
var feedBarWidth = $('#feedBar').width();
$('#feed').css('width', bodyWidth - (subNavWidth + feedBarWidth));
Use a grid system such as the one in Foundation 3. When placed on a div representing an element of the grid, min-width behaves just fine.
To get min-width to work without a grid, use a CSS rule that inserts an invisible pseudo-element with the desired minimum paragraph width.
p:before {
content: "";
width: 10em;
display: block;
overflow: hidden;
}
Further details are at the source where I learned this.