Different text overflow properties for display: block vs display: inline [closed] - html

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 13 days ago.
Improve this question
This question is too nuanced for me to find an answer on Google and I've been struggling with it for so long trying to find a good answer.
I want span elements to cut off with an ellipsis when they overflow a div. The problem is that this behavior only works when I set the span's display to block, but this causes the other spans who aren't long enough to overflow the div have their widths expanded, when I want them to stay only the size of their inner content.
Here's a demonstration in an online editor - try changing display from "block" to "inline" to see what I mean.
http://tpcg.io/_0UNNZM
Any help would be appreciated, I am new at css and it has been treacherous to learn so far. :)

My solution is a bit hacky. I gave the second span a classname.
<span class="secondElement">000</span>
I then set the second element to display: inline:
.secondElement {
display: inline;
}
It solved the issue. Here is the working solution: http://tpcg.io/_PJLSI5 .
Edit:
Since the elements are dynamic. I implemented the change the functionality with the help of JavaScript.
First, I add a class name spansContainer so that I can reference it with JavaScript. And I also removed the class on the second span element:
<div class="spansContainer">
<span>0000000000000000000000</span>
<br />
<span>000</span>
</div>
In the CSS, I set display to inline and added a new class block, that sets display to block:
span {
background-color: #0000ff80;
overflow: hidden;
text-overflow: ellipsis;
display: inline; /* set it to inline*/
}
/* this class is added to the span element using JavaScript */
.block {
display: block;
}
From there, I wrote the JavaScript solution:
const spansContainer = document.querySelector(".spansContainer");
const spanElements = document.querySelectorAll("span");
// add the class `block` to all span elements
// that have a width greater than the parent
// on page load.
spanElements.forEach((spanEl) => {
if (spanEl.offsetWidth > spansContainer.offsetWidth) {
spanEl.classList.add("block");
}
});
// configuration of the observer:
config = {
attributes: true,
childList: true,
characterData: true,
subtree: true,
};
// create an observer instance
var observer = new MutationObserver(function (mutations) {
// loop through the mutated span elements
mutations.forEach(function (mutation) {
const spanEl = mutation.target.parentElement;
if (spanEl.offsetWidth > spansContainer.offsetWidth) {
spanEl.classList.add("block");
} else {
// remove class 'block' if span's width is
// smaller than the div
spanEl.classList.remove("block");
}
});
});
// pass in the target node, as well as the observer options
observer.observe(spansContainer, config)
I created the codepen for the solution here: https://codepen.io/Stanleyu/pen/bGjJwxO

Related

Ag-grid column menu: display overflow text

By default Ag-grid sets a fixed column menu width. Their documentation has an example of setting the column menu width to a different fixed value. The issue with this approach is that every column will have the same menu width.
Is there a way to dynamically set the column menu width based upon the column's filter list values? The following has no effect:
.ag-set-filter-list {
width: auto;
}
Similarly word wrapping could also solve this issue, but is also not working:
.ag-set-filter-list {
overflow-wrap: break-word;
}
I also tried using the postPopup callback to adjust styling after rendering, with no luck:
created() {
this.postProcessPopup = (params) => {
if (params.type !== 'columnMenu') {
return;
}
params.ePopup.style.overflowWrap = "break-word";
params.ePopup.style.width = "auto";
}
}
Digging into Ag-grid's filter list styling more, I realized that the filter items are absolutely positioned and use top values for placement. This made it difficult to wrap filter values without having them collide with each other.
I contacted Ag-grid support and they confirmed that dynamic filter list widths are not supported. They did mention their tooltips feature though, which works for my use case.
I modified that example in two ways:
Only show tooltips for filter list values that are longer and will be cut off by the edge of the filter menu.
Only show tooltips for values in the filter list, not for rows in the grid.
Here's my version of a custom tooltip with the above modifications:
export class GridColumnFilterTooltip {
init(params) {
const FILTER_VALUE_CHARACTER_LIMIT = 28;
this.tooltip = document.createElement("div");
if (
params.location === "setFilterValue" &&
params.value.length > FILTER_VALUE_CHARACTER_LIMIT
) {
this.tooltip.classList.add("grid-column-filter-tooltip");
this.tooltip.innerHTML = params.value;
}
}
getGui() {
return this.tooltip;
}
}

Getting "natural" display type for HTML elements?

I have a a web page where various fields are shown or hidden by toggling between "display:block" and "display:none". However, I added some extra stuff to the page and discovered that I needed to special-case several tags: TD needs to use "display:table-cell:, TR needs to use "display:table-row", and so on...
Is there any general off-the-shelf solution to this (i.e. look up the "natural" display type based on the tag name) or am I stuck with creating a JS object by hand which lists tag names and the corresponding display types?
You can apply revert to display property to set the element to it's original value and get the original value by Javascript.
const getOriginalDisplayProperty = (elem) => {
const modifiedDisplayProperty = getDisplayProperty(elem); //store modified display property
elem.style.display = "revert"; //revert to original display property
setTimeout(() => {
elem.style.display = modifiedDisplayProperty; // Again set original display property
}, 0);
return getDisplayProperty(elem);
};
const getDisplayProperty = (elem) =>
window.getComputedStyle(elem, null).display;
getOriginalDisplayProperty(document.querySelector(".test"));
getOriginalDisplayProperty(document.querySelector(".test-span"));
div {
display: inline;
}
span {
display: flex;
}
<div class="test"></div>
<span class="test-span"></span>

How to apply a class to a child if all other children are hidden?

I know that this is super simple with jQuery, although I am after a CSS only solution (if possible).
I have a list of divs, with the last item being an error message. I have a simple filtering system, and if none of the divs match the selected filter, I would like to display the error div.
HTML Structure:
<div id="listHolder">
<div class="listItem" data-filter-class="["filter1"]"></div>
<div class="listItem" data-filter-class="["filter2"]"></div>
<div class="listItem" data-filter-class="["filter1"]"></div>
<div class="listItem" data-filter-class="["filter4"]"></div>
<div class="errorItem">Nothing to display here</div>
</div>
What I am trying to achieve:
If a div does not match any of the filters, my filter plugin gives them the class of inactive. Hence, I need to check if all divs with the class of listItem also have the class of inactive to give the errorItem class the style of display:block.
FYI I am using the Wookmark plugin for my list and filtering system. I am also using LESS.
Sure it's possible: http://jsfiddle.net/rudiedirkx/7b1kyfz3/3/
You want to hide the last item if a previous item is not hidden:
.listItem:not(.inactive) ~ .errorItem {
display: none;
}
The demo uses JS just to toggle the inactive class, not for display logic of the errorItem.
I still agree with all the smart people here though: JS can probably do this better. You're using it already anyway.
The problem you have is in your requirement:
I need to check if all divs with the class of listItem also have the class of inactive to give the errorItem class the style of display:block
While we can set a style for the final <div> element based on its preceding siblings, we can't (without knowing how many there might be) 'check if all divs' have the inactive class. We can, however, use the sibling combinator (+) and a cumbersome selector:
.errorItem {
display: none;
}
.listItem.inactive + .listItem.inactive + .listItem.inactive + .listItem.inactive + errorItem {
display: block;
}
This is, however, ridiculous (especially if there's a dynamic number of elements preceding the .errorItem element.
If there's a class-name applied for an element which does match the supplied filters, active for example, this is much simpler, and achieved by:
.errorItem {
display: block;
}
.listItem.active ~ .errorItem {
display: none;
}
Also, as pointed out in the comments, the negation operator is also available (though, obviously, it depends on implementation by the browser in use), which would lend itself to the selector:
.errorItem {
display: block;
}
.listItem:not(.inactive) ~ .errorItem {
display: none;
}
On the whole, I'd strongly suggest using JavaScript to support this functionality, especially since the use of Wookmark implies JavaScript (if not necessarily jQuery) use in the same site already.
Native JavaScript:
function hasPrecedingSibling (elem, state) {
if (!state) {
return false;
}
var found = false,
cur = elem;
while (cur.previousElementSibling && found === false) {
if (cur.classList.contains(state)) {
found = true;
}
else {
cur = cur.previousElementSibling;
}
}
return found;
}
[].forEach.call(document.querySelectorAll('.errorItem'), function (err) {
err.style.display = hasPrecedingSibling (err, 'active') ? 'none' : 'block';
});

Disconnect between adding a class and CSS getting applied [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I'm having some annoying issues between Bootstrap/JQuery/my own CSS, tell me if this sounds like a problem you know how to fix.
I'm implementing my own "slider", with AJAX calls loading content onto the page depending on the navigation the user does. The problem comes in with my navbar. When an onhashchange event happens, I'm loading the correct content in, clearing the active class from the <li> element, and re-adding the active class to the appropriate <li> element.
Unfortunately, setting the active class isn't causing the appropriate CSS I have written to be applied, a slight darkening. There could be a million things causing THAT, I realize. But hardcoding an active class gives exactly the desired result. I don't know where the disconnect is. I ask myself, is a page loading problem getting in the way of the CSS being applied? I don't know.
Thanks in advance.
HTML:
...
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="sections nav navbar-nav">
<li>Call</li>
<li>Police</li>
<li>Charges</li>
<li>Jail</li>
<li>Courts</li>
<li>Resources</li>
</ul>
...
</div>
...
My CSS:
.navbar {
background-color: #231f20;
}
.navbar .sections>li>a:hover {
background-color: #4f4c4d;
}
/* Overriding */
.navbar a { color: #DDD !important; }
.navbar a:hover { color: #AAA !important; }
.navbar-nav>.active>a { background-color: #4f4c4d !important; }
My JS:
/* Constants */
var elem = $('.sections li a');
var pages = [];
for(i=0; i<elem.length; i++) {
//console.log(elem[i])
pages[i] = elem[i].hash;
}
var first = 0;
var last = pages.length;
...
function loadPage(hash, callback) {
/* Loads the content inside the "#main" element on the
page found at <url> into the "#main" element of the
current page. Then sets the links and buttons
accordingly. */
url = hash.split('#')[1] + '.html'
$('#main').load(url + "#main", callback);
setLinks(hash);
}
function setLinks(hash) {
for (i=0; i<=last; i++) {
if (pages[i] == hash) {
page_num = i;
}
}
var previous = page_num - 1;
var next = page_num + 1;
...
$('.sections li').removeClass('active');
$('.sections li').eq(page_num).addClass('active');
}
$(document).ready(function() {
...
$(window).on('hashchange', function() {
loadPage(window.location.hash);
});
});
You should make use of the callback functionality offered in the function loadpage. You are doing an asynchronic call, and directly applying the css. However, the page has not been updated yet (it takes some time). You should do something like this (only the updated functions):
function loadPage(hash, callback) {
/* Loads the content inside the "#main" element on the
page found at <url> into the "#main" element of the
current page. Then sets the links and buttons
accordingly. */
url = hash.split('#')[1] + '.html'
$('#main').load(url + "#main", callback);
// setLinks(hash); <-- don't do this, it will be executed to early!
}
$(document).ready(function() {
...
$(window).on('hashchange', function() {
loadPage(window.location.hash, setLinks); // <-- making use of the callback functionality
});
});
And remove the setLinks call from the loadPage function itself. By passing it in as the callback function, it will get executed once the $('#main').load is finished.

Drop down input in IE8

How can I make the drop down show all the content of one option when it is expanded? If an option in the drop down is, for instance, a whole sentence and select tag width is small, the user in IE will not be able to read whole option. This is not the case in Mozilla where the whole content is shown when drop down is expanded.
Is there any way to avoid this behavior in IE8,
Thanks
I had a similar constraint when working against IE8 and the oh so famous drop down list truncating. I have multiple drop down lists on my page, one after another, some inside top nav content, and IE8 decides to cut off my attribute option text properties. Now, like many of us, I don't want to set the width obscurely large, so this option is out of question.
After a lot of research, I couldn't find a great answer, so I went ahead and fixed it with jQuery and CSS:
First, let's make sure we are only passing our function in IE8:
var isIE8 = $.browser.version.substring(0, 2) === "8.";
if (isIE8) {
//fix me code
}
Then, to allow the select to expand outside of the content area, let's wrap our drop down lists in div's with the correct structure, if not already, and then call the helper function:
var isIE8 = $.browser.version.substring(0, 2) === "8.";
if (isIE8) {
$('select').wrap('<div class="wrapper" style="position:relative; display: inline-block; float: left;"></div>').css('position', 'absolute');
//helper function for fix
ddlFix();
}
Now onto the events. Since IE8 throws an event after focusing in for whatever reason, IE will close the widget after rendering when trying to expand. The work around will be to bind to 'focusin' and 'focusout' a class that will auto expand based on the longest option text. Then, to ensure a constant min-width that doesn't shrink past the default value, we can obtain the current select list width, and set it to the drop down list min-width property on the 'onchange' binding:
function ddlFix() {
var minWidth;
$('select')
.each(function () {
minWidth = $(this).width();
$(this).css('min-width', minWidth);
})
.bind('focusin', function () {
$(this).addClass('expand');
})
.change(function () {
$(this).css('width', minWidth);
})
.bind('focusout', function () {
$(this).removeClass('expand');
});
}
Lastly, make sure to add this class in the style sheet:
select:focus, select.expand {
width: auto;
}