Maintaining Vertical Rhythm on arbitrary images - javascript

I would like to be able to maintain vertical rhythm on a page that contains images of unknown heights. I found this but am using vanilla-js rather than jquery so a jquery plugin is out of the question. The other answer requires that the baseline be set in javascript. I already have it set in my SCSS files! I'm a very lazy programmer and don't want to type it twice. Wait, I didn't say that. I meant I'm concerned about the maintainability of duplicating hard-coded values all over the place.
here is another solution that I have to reject because I don't like all that extra markup over style concerns. It reminds me of the days when you had to nest <div> tags four deep just to get rounded corners.
It occurred to me to use generated content to pass JSON to the javascript. I thought I was a genius but then found this example using the exact same method.
Is there a better way of doing this?
All I really want is a way to specify that the height of an element needs to be a multiple of some given value. Is there really no way to do this with just CSS? The answers I've seen say there isn't. I feel like calc could almost do the job but am not smrt enough to figure it out. Is there a better way of getting the value to the javascript?
Thanks in advance.

It occurred to me that it is better to use CSS variables and then read those values from javascript as documented here.
This has the advantages of
using the cascade to allow multiple regions of the page to each have their own vertical rhythm.
not requiring parsing the content of the ::after psuedo-element as JSON.
The browsers are apparently inconsistent regarding how the escape embedding quotes in the content attribute.
One downside is that custom attributes are not as widely supported as pseudo elements. This way will break on more browsers. Because it's only cosmetic, I find that acceptable.
const foo = document.getElementsByClassName('foo')[0];
const bar = document.getElementsByClassName('bar')[0];
const fooStyles = window.getComputedStyle(foo);
const barStyles = window.getComputedStyle(bar);
const fooVR = fooStyles.getPropertyValue('--vertical-rhythm');
const barVR = barStyles.getPropertyValue('--vertical-rhythm');
foo.innerHTML = '--vertical-rhythm: ' + fooVR;
bar.innerHTML = '--vertical-rhythm: ' + barVR;
:root {
line-height: 1.5rem;
/* $line-height */
--vertical-rhythm: 3rem;
/* 2 * $line-height */
}
.foo {
--vertical-rhythm: 6rem;
/* 4 * $line-height */
}
<div class="foo"></div>
<div class="bar"></div>

Related

How to get the inherited values of element from JavaScript

Okay, so I've a script that gets the CSS property value of a clicked element. For this, I avoided window.getComputedStyle() because it basically converts rem values to px and so on...
Instead, I've used CSSStyleSheet.cssRules just to keep the originality of the actual given units and not converting them.
And this does works fine! but it fails to capture CSSRules that are inherited from the parent element since the styles are not directly applied to the element.
For example:
<style>
#new {
font-size: 2rem;
}
</style>
<div id="new">
<h1 class="h1">This is a heading</h1>
<!––Here h1 is inheriting font-size from div that can't be catched by CSSRules––>
</div>
For this case, getComputedStyle() works the best as CSSRules failed to catch the inherited properties but again, the problem of units arises so I cannot use that.
Or maybe something to get the metric unit of an element? 🤷‍♀️ That would do the job too!
Although Chrome seems to have figured this out perfectly:
It's 2022 and I've checked other answers too but seems like nobody has figured this out yet. What's the current solution to this? Or the best hack?
Edit1:
I want the same string as defined in the CSS by the user. Like: calc(2rem + 1vh) And with CSSRules it is working but it doesn't works with inheritance because it's not even catching the property! ComputedStyle does that but in px I'm kinda stuck here.
Edit2:
I've chosen Lajos Arpads answer as the accepted one because of the help I recieved in the comments (not the actual answer itself). The solution is going to be labor intensive so it's something I've to do.
You can simply implement a pixel-to-rem converter and use that:
function convertPixelsToRem(pixels) {
return ((pixels.replace("px", "") / getComputedStyle(document.documentElement).fontSize.replace("px", "")) + "rem");
}
console.log(convertPixelsToRem(window.getDefaultComputedStyle(document.getElementById("new").querySelector(".h1"))["font-size"]));
<style>
#new {
font-size: 2rem;
}
</style>
<div id="new">
<h1 class="h1">This is a heading</h1>
<!–– Here h1 is inheriting font-size from div ––>
</div>
EDIT
You could do something like this:
getOriginalRule(ruleName, ruleValue, item) {
while (hasSameRule(item.parentNode, ruleName, ruleValue)) item = item.parentNode;
//return the rule value based on the item via CSSStyleSheet.cssRules
}
EDIT2
As per the ideas discussed in the comment section, with the goal being to be able to gather the raw rules applied either directly or by inheritance to nodes, there are two main solutions:
one can loop through the rules, find the elements they apply to and then loop the DOM tree to descend the raw rules where they were not overriden
one can loop the DOM tree from top to bottom and find all nodes, compare each node's rules with its parent's rules and if they differ, descend the parent's rules
The main difference between the two is that the first is starting with all the CSS rules, while the latter only uses the values.

Use jQuery to get css properties of a class/id that that doesn't exist in the page

As it said in the title. I want this javascript...
$("#mrNotAppearing").css("background-color");
to return "red" based on this css...
#mrNotAppearing {
background-color: red;
}
given that there are no elements in the document that actually have the id mrNotAppearing
I'm using media query checks with jQuery to get window widths as seen here and I thought it might be nice to use some "dummy" css that definitely won't get in the way of anything.
I'm also open to other suggestions that achieve the same result.
Plan B, I'll just go with actual css or add some dummy property to body?
Updating for clarity:
It can be difficult to sync javascript that requires particular window widths with media query widths in the css, which can cause layout problems.
Instead, you can query the status of the css itself. As so:
body {
background-color: blue;
}
#media (min-width: 42em) {
body {
background-color: red;
}
}
Then, in the javascript:
if($(body).css("background-color")==="red"){
// we know down to the pixel that it's safe to trigger the javascript
// because the media query went off.
}
All I'm trying to do is add a dummy entry in the css that will be used solely for triggering the javascript. I could use an existing property--and may have to--but I'd like to make it explicit what I'm doing. Or I'm at least toying with the idea.
I apologize for the confusion. I was going for brevity.
P.S. the whole point of the question is to use a style that will 100% not be appearing in the document. And will never change, even if the layout does.
EDIT: Ha, okay, final answer. em does indeed return as px. So...
I'm going to answer my own question because I'm pretty sure it isn't making sense to anyone. Also, I don't know if this is a good idea, but it seems to work for my purposes. So, my solution:
Style the <style> tag. It's in the DOM, it's not structural, and jQuery can get css properties from it. Like so...
style {
width: 672px;
}
and then...
$("style").css("width");
will return 672px
I'm probably over-thinking this. And still probably not making sense. And I have no idea if this works on any browser but Chrome or if it's a terrible idea for some reason, but I think it's kind of appealing, semantically.
Any other thoughts?
You have access to all css rules through document.styleSheets, there is no need to apply to an element.
https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet
Here is another answer on how to get the style based on a class name:
How do you read CSS rule values with JavaScript?
EDIT
Although, it would be a lot easier to render the element off canvas for a brief moment:
var $dummy = $('<div>').addClass('class1 class2 class3').css({position: fixed, left: 100%}).appendTo('body');
// collect all info you need here;
$dummy.remove();

Is it okay to rely on javascript for menu layout?

I have a website template where I do not know the number of menu items or the size of the menu items that will be required. The js below works exactly the way I want it to, however this is the most js I've every written. Are there any disadvantages or potential problems with this method that I'm not aware of because I'm a js beginner? I'm currently manually setting the padding for each site. Thank you!
var width_of_text = 0;
var number_of_li = 0;
// measure the width of each <li> and add it to the total with, increment li counter
$('li').each(function() {
width_of_text += $(this).width();
number_of_li++;
});
// calculate the space between <li>'s so the space is equal
var padding = Math.floor((900 - width_of_text)/(number_of_li - 1));
// add the padding the all but the first <li>
$('li').each(function(index) {
if (index !== 0)
{
$(this).css("padding-left", padding);
}
});
You can do this hackily in CSS, using display: inline-block, and text-align: justify
<ul>
<li>thing</li>
<li>thing2</li>
<li>thing3</li>
<li>thing4</li>
<li class="hack"></li>
</ul>
And then:
ul { text-align: justify }
li { display: inline-block }
li.hack { width: 100% } /* force the justified text to wrap */
Demo
​
Yes, there are disadvantages of using JS for formatting.
It is strongly recommended to avoid using JS for formatting and positioning, use CSS whenever possible.
Javascript is interpreted and run very differently from browser to browser, from OS to OS, from OS/browser version to version.
CSS rendering is a native browser engine function and its rendering priority is higher than that of JS.
CSS rendering is much more speedy than JS.
Etc.
What you are doing now I would never suggest doing. IMHO, this is a very wrong approach. JS is absolutely definetely misused in this case. You have to use CSS for this task, and I would suggest posting a question about how to use CSS correctly for this task.
I would suggest having a default spacing between them in a way that would not push them out of their container. The extra javascript to enable them to space equally should be an enhancement only.
I think the answer to your question is, if it works, then it works (and will continue to work), but that doesn't mean that this is the best way to handle it. If you *care about the best way, then investigate how to improve your approach using mostly (or even exclusively) CSS. If you're just looking to get the job done, and it's working, then you're good to go.
Depending on your site visitors, there will be around 3% who visit you with JS disabled. And you want the site to work for them to. Maybe not the unnessecary parts of the site but you want the critical parts to work. Navigation is one of the most important parts of a website.
Make sure the navigation works without JS (doesn't have to be as fancy as with JS) and then you could make some improvements with JS.
You don't need JavaScript as long as you can rely on a CSS algorithm that adapt width to its content: the table layout algorithm :)
See http://jsfiddle.net/r9yrM/1/ from my previous answer for examples.
Don't forget to have a minimum padding on each "cell", text stuck to a border isn't very readable (and ugly). You'll also probably want text-align: center on cells (last CSS rule).
With JS, you could decide of a maximum number of tabs (or a minimum "reasonable" width) and above (below) that number, add a class on the parent that will trigger each tab to render as float: left and block and not table-cell anymore. Then it'll occupy 2 or more lines (like the extension Tab Mix Plus on Firefox)
Note: there're at least 2 algorithms for table: with and without table-layout: fixed, depending on freedom left to the browser when adapting.
Note on your jQuery code above: "each li except the first" can be expressed by $('li + li') (the first one isn't preceded by a li)

Quickly repaint array of unicode symbols in JavaScript

I want to change background/foreground color of many symbols with the same CSS class. Right now I'm doing it with jQuery — like $('back_COLORED').css('background-color', '#00FF00'), but this approach is slow when there are many elements with such class (>900).
Seems it's because jQuery don't change CSS rules itself, but finds all elements one-by-one and applies inline styles to them. At least, this is what I see in inspector. So, the question is:
How can I change the CSS rules itself?
Will it be much faster?
Can I make it cross-browser (IE6 doesn't count)?
UPD: I'm trying to make some kind of color scheme editor. The source is at http://github.com/kurokikaze/cinnabar/. Don't mind PHP things, editor is fully client-side (with just some libraries fetched from the net).
UPD2: Tried canvas approach, still slow. Canvas branch is at http://github.com/kurokikaze/cinnabar/tree/canvas.
The most cross-browser friendly way to override a class definition is to write a new rule and add it to the end of the last stylesheet in the document. You can edit an existing style rule, but even some recent browsers can make it difficult.
function newRule(selector, csstext){
var SS= document.styleSheets, S= SS[SS.length-1];
// this example assumes at least one style or link element
if(S.rules){
S.addRule(selector,csstext,S.rules.length);
}
else if(S.cssRules){
S.insertRule(selector+'{'+csstext+'}'),S.cssRules.length)
}
}
newRule('.someclass','background-color:#0f0');
You can add as many 'property:value;' bits in the csstext as you need.
Remember to prefix a '.' to a class name or a '#' to an id,
and the css must be written as a style rule (with-hyphens, not camelCase).
Of course, it will not override inline styles, and it is overkill for small, local changes.
It also may make the redrawing of the page more obvious than changing one element at a time,
but it may be just what you need here.
There are different ways depending on which browser you are dealing with. This is documented on Quirks Mode.
Some libraries provide an abstraction layer, such as YUI's StyleSheet utility.
There should be a significant performance boost since you aren't using JS/DOM to cycle through all the elements.
Another approach would be to predefine your styles:
body.foo .myElements { … }
And then edit document.body.className
If you can select the parent div by id, maybe you could select by tag inside it? Or are there elements of the same kind that should change color and that should not, inside the parent?
It would be nice to have an idea of what you're building here. 900+ objects seems to be a lot... maybe a completely different approach could be used? Canvas, SVG?
Try hiding the items you want to change before changing them, make the change and then display them again. This is common practice to speed up things as you minimize the repaint events in the viewport. In this case when you only setting one css property it might not be that of a benefit but it´s worth a try I say.
Try:
$('back_COLORED').hide();
$('back_COLORED').css('background-color', '#00FF00');
$('back_COLORED').show();
or
$('back_COLORED').hide().css('background-color', '#00FF00').show();
I would stick in trying changing a CSS property, instead of parsing the DOM.It is about the CSS engine vs. DOM+JS here, and the winner is clear.
It happens I just uploaded a tiny library that replaces CSS by Javascript: jstyle
This is may be an overkill, but you will find in the source code of jstyle.js all the code you need to update cross browser the CSS properties of your page.
I think a better solution would be to write a more specific CSS rule (that would override the normal colour) that can be activated by simply changing one element's css class.
So for example if you had the following structural markup:
<div id="container">
<span class="colored">Test 1</span>
<span class="colored">Test 2</span>
</div>
And CSS:-
.colored { background-color: red; }
.newcolor .colored { background-color: blue; }
Then in your jquery you add the .newcolor class to the container div:-
$('#container').addClass('.newcolor');
When you do that the second CSS rule will override the first because it is more specific.
Inject the css code into a style tag:
var style = $('style').attr({
type:"text/css",
media:"screen",
id:'changeStyle'
}).html('.tempClass { color:red } .tempClass p { background:blue }').prependTo('body');
and on every changes on your color with color picker you only rewrite the html inside of #changeStyle tag.
Have no idea if it works (didn't tested) but you should give a try.
This is jQuery pluggin for work with css rules: http://flesler.blogspot.com/2007/11/jqueryrule.html
not sure about its performance, but worth a try.

Limit displayed length of string on web page

I'm looking for a technique (javascript, CSS, whatever ???) that will let me control the amount of a string that is displayed. The string is the result of a search (and therefore not initially known). A simple Character count approach is trivial, but not acceptable, as it needs to handle proportional fonts. In otherwords if I want to limit to say 70 pixels then the examples below show different character counts (9 and 15) both measuring the same:-
Welcome M...
Hi Iain if I've ...
If you look at Yahoo search results they are able to limit the length of title strings and add ellipsis on the end of long strings to indicate more.
(try site:loot.com wireless+keyboard+and+mouse to see an example of Yahoo achieving this)
Any Ideas?
Perhaps the CSS property overflow: hidden; can help you, in conjuntion with width.
Using a span with fixed width, overflow-x:hidden and white-space:nowrap would be a start.
To get the elipsis in a cross browser scenario will be difficult. IE has text-overflow:elipsis but that is non-standard. This is emulated with -o-text-overflow in Opera. However mozilla doesn't have this. The yahoo Javascript APIs handle this.
Yahoo does this server-side, the truncation and elipsis ('...') is returned in the HTML. Presumably this is done on a character count, and if thats not an option for you then server-side is out.
Other than overflow: hidden I'm not sure CSS can help you here. You could measure the width of the containing element using Javascript, and truncate the text based on that. This could be used in conjunctin with overflow:hidden; so the text elements don't just resize all of a sudden, but you may have to extract the text and add a temporary element onto the page somewhere to do the measurement. Depending on the number of elements to truncate this might not work very well.
Another slightly hacky option is to measure the width of an element containing the letter 'W', then do a character count and truncate if (char_count * width_of_w) > desired_width.
You can use text-wrap: none; to stop text wrapping onto new lines, although this is a CSS3 property and last I checked was only supported by IE (imagine my shock when I found that one out!).
For a cross-browser pure-CSS solution, take a look at Hedger Wang's text-overflow:ellipsis prototype, here:
http://www.hedgerwow.com/360/dhtml/text_overflow/demo2.php
In CSS: .class-name{
width: 5em;
white-space: nowrap;
text-overflow: ellipsis; }
Hope it can help you.

Categories

Resources