I searched online for the correct syntax to reference a CSS class, instead of an HTML element, but was unable to find anything helpful.
I would like to modify the code below to reference any DIV of class buy_content "div.buy_content" instead of the body element.
Small Text
Medium Text
Large Text
There is no "JavaScript syntax" for what you're asking for. Newer browsers support an API called "getElementsByClassName", so you could do this:
function setSize(sz) {
var elements = document.getElementsByClassName('buy_content');
for (var i = 0; i < elements.length; ++i) {
if (elements[i].tagName === 'DIV')
elements[i].style.fontSize = sz;
}
}
<a href='#' onclick='setSize("1em"); set_cookie(...);'>Small</a>
You can find a "patch" for "getElementsByClassName" support here.
<a href="#" class="clickie size-1" >Small text </a>
<a href="#" class="clickie size-2" >Medium text </a>
<a href="#" class="clickie size-3" >Large text </a>
You should change the markup not to rely on inline javascript.
// bind the event handler to all <a> tags
var as = document.getElementsByTagNames("a");
for (var i = 0, ii = as.length; i < ii; i++) {
as[i].onclick = setText;
}
function setText(ev) {
// get the em size from the class
var size = /[.]*text-([\d][.]*)/.exec(ev.target.className)[1]
var divs = document.querySelectorAll("div.buy_content");
// set the style on all divs.
for (var i = 0, ii = divs.length; i < ii; i++) {
divs[i].style.fontSize = size + "em";
}
}
There are issues with browser support (mainly IE7 and lower) so you need some more boilerplate to make it work.
You can't really do this (easily/readably/cleanly) with inline and stock JavaScript because the JavaScript DOM API doesn't provide a way to reference a CSS class since this isn't part of the DOM. You would have to populate an array or list with HTML elements that have that class applied to them and then iterate over the collection.
JQuery provides selectors and iterators to make this very simple, but if you can't use libraries then doing this inline isn't a good idea. Put it in a function in a script block or an external .js file.
EDIT:
A few people pointed out querySelectorAll, which will select by class but from what I have read isn't completely cross platform (doesn't work on IE below IE 8).
Further, to clarify on my original post, when I said that the DOM API doesn't allow you to access an element by class, what I meant was that it couldn't be done with DOM traversal. querySelectAll or the JQuery selectors perform DOM traversal with functions that inspect elements and their properties, retrieve the objects, and populate collections. Even getElementById performs attribute inspection. I suppose, in retrospect, it's a moot point, but since he wasn't using selectors or attribute queries in his original code I thought that he was asking if there was JS syntax that was as simple as what he was currently using. That's why I mentioned functions. In my head, even something like getElementById is a function since, well, it is a function.
I believe what you are looking for is insertRule (this is exactly what you asked for... kinda):
document.styleSheets[document.styleSheets.length-1].insertRule('div.buy_content {font-size: 1em}',document.styleSheets[document.styleSheets.length-1].length)
document.styleSheets[document.styleSheets.length-1] is your last stylesheet.
the new rule will go at index document.styleSheets[document.styleSheets.length].length
http://www.quirksmode.org/dom/w3c_css.html#t22
also... deleteRule:
http://www.quirksmode.org/dom/w3c_css.html#t21
BUT, a better way to go would be to getElementsByClassName, loop through em, check their nodeName for "DIV", then apply the styles the old fashioned way.
Leverage CSS to do the selection work for you:
body.smalltext .buy_content { font-size: 1em; }
body.mediumtext .buy_content { font-size: 2em; }
body.largetext .buy_content { font-size: 3em; }
...
<input type="button" value="Small text" id="smalltext"/>
<input type="button" value="Medium text" id="mediumtext"/>
<input type="button" value="Large text" id="largetext"/>
...
document.getElementById('smalltext').onclick= function() {
document.body.className= 'smalltext';
};
document.getElementById('mediumtext').onclick= function() {
document.body.className= 'mediumtext';
};
document.getElementById('largetext').onclick= function() {
document.body.className= 'largetext';
};
My first suggestion to answer your exact question:
If your project is bigger in scope than just this one thing:
Download jQuery
Use code:
$('div.buy_content')
Which returns a jQuery array object of all the divs which you can further manipulate.
My second suggestion based on thinking more deeply about what you're trying to do:
Either completely replace the stylesheet in script or modify the existing stylesheet to change the style. Don't loop through all the DIVs in the document and change their style assignment, instead change the meaning of their already-assigned style.
Related
Our Squarespace site has a catalogue containing products from multiple brands. I'm trying to ensure the brand name stands out by making it bold but given the way Squarespace works, I need to add Javascript into the page to manipulate the html.
Using Chrome Dev tools on the product titles, I can see the html class is called '.ProductList h1.ProductList-title'.
I've tried implementing the below, but haven't had much luck so far - am I even on the right track?
function changeBrandName()
{
var prodList = document.getElementsByClassName(".ProductList h1.ProductList-title");
for (i = 0, len = prodList.length; i < len; i++)
{
prodList[i].style.color = 'red';
}
}
window.onload = changeBrandName();
Squarespace class structure:
<section class="ProductList-overlay">
<div class="ProductList-meta">
<h1 class="ProductList-title">Vifa - Pebble Grey Oslo Loudspeaker</h1><style></style>
<div class="product-price">
<span class="sqs-money-native">0.00</span>
</div>
</div>
</section>
(this is one of the pages we're displaying products https://www.manilva.co/catalogue-electronics/).
Take a look: https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
when using getElementsByClassName, you do not need to pass in CSS selectors, like you have done. You just need to pass in the actual name of the classes. Or, use the querySelectorAll with the parameters you had originally. querySelector, as daksh mentioned, will only return the first element that matches
function changeBrandName()
{
var prodList = document.querySelectorAll(".ProductList h1.ProductList-title"); //returns static NodeList of all elements in DOM that match the provided classes
for (i = 0; i < prodList.length; i++)
{
prodList[i].style.color = 'red';
prodList[i].style.fontWeight = 'bold'; //W is capital
}
}
You've indicated that you must use Javascript. However, Squarespace supports custom CSS (currently under Design > Custom CSS while editing your site). Having read through the question, I see no details that preclude the use of CSS (though perhaps such details were simply left out).
If using CSS is an option, inserting the following via Custom CSS is all that is needed:
.ProductList h1.ProductList-title {
color: red;
font-weight: bold;
}
If for some reason you want to target only a specific collection, you can add further specificity to the selector via the collection ID, used as the id attribute on the body element:
#collection-5c1cf955898583ce09da99a0 .ProductList h1.ProductList-title {
color: red;
font-weight: bold;
}
If you choose to go the CSS route, be sure you evaluate and remove any previous code you've added related to this particular need.
Sounds simple, huh. Lot's of answers i found but all use jQuery or ProtoType. I want plain JavaScript. It shouldn't be that hard, but JavaScript is not my thing; no central documentation means searching for ages and not finding what i want.
Consider the following HTML code snippet:
<div class="central_0"> .. </div>
<div class="central_1"> .. </div>
<div class="central_2"> .. </div>
Now I want to use JavaScript to do things with those DIVs.
function processDivElements()
{
// search for relevant DIV classes
var divArray = document.getElementsByClass.regex('/^central_.*$/');
// do stuff with the DIV elements found
foreach (divArray as divElement)
{
divElement.style.background = '#f00';
};
}
Can anyone help me translate this to proper plain JavaScript? I use classes, not IDs. I prefer using a regular expression.
The jQuery solution is really nice:
var $divs = $('div[class^="central_"]');
If you only want to support newer browsers, you can use document.querySelectorAll() to do essentially the same thing:
var divs = document.querySelectorAll('div[class^="central_"]');
If you want to support older browsers, the code gets horrible:
var all_divs = document.getElementsByTagName('div');
var divs = [];
for (var i = 0; i < all_divs.length; i++) {
var div = all_divs[i];
if (div.className.match(/^central_\d+$/) {
divs.push(div);
}
}
Also:
I use classes, not IDs. I prefer using a regular expression.
Your classes are unique and are really functioning like IDs, which isn't really the intended use of classes. Structure your HTML like this instead:
<div id="central_0" class="central">...</div>
<div id="central_1" class="central">...</div>
<div id="central_2" class="central">...</div>
Now, the JavaScript becomes simpler:
var $divs = $('.central'); // jQuery
var divs = document.querySelectorAll('.central'); // Newer browsers
var divs = document.getElementsByClassName('central'); // Older browsers
As the others have mentioned you can't directly support a regex select on the getElementsByClassName method call.
But I will point out these other issues with your code, since you are new to javascript.
Using classes is fine, but your making more work for yourself by writing up your html like that.
Instead of the central_0....central_2 if they are all basically operating on the same css rules, you should write them like this central zero....central two then your central class can have identical rules, while you can assign any differences to the # classes. This way your also adhering to the DRY principle.
Also you should really consider sticking to the best practices for the language. If your not assigning css rules to your elements with those classes then you should be using id's, plus it makes your life much easier.
There is no way to get the matched elements by regex directly, the only thing you could do is to get all the elements by something (like: TagName, Name, etc..) and then filter the elements by regex.
With your html sample, you could only get all the element by TagName, and use regex to check the className by regex.
One quicker way to do so is to create a simple <style> as follows:
<style>
div[class^="central_"] {
background-color: #f00;
}
</style>
Therefore, as you look for plain javascript, useless to say that you can add <style> tags at will, by using javascript. A whole HTML example as follows:
<html>
<head>
</head>
<body>
<div class= "central_1">
central 1
</div>
<script>
var css = "<style>div[class^=\"central_\"] {background-color: #f00;}</style>";
var list = document.querySelector("head"); list.innerHTML += css;
</script>
</body>
</html>
Is there any way you can set an element to be a master and have all other elements on a page appear and behave in exactly the same, same style, same code, same attributes, same values?
<input id="btnBack" name="btnBack" type="button" value="Back" disabled="disabled" style="margin-right: 10px" />
$('#btnBack').click(...do stuff);
<input master="btnBack" />
Or failing this is there any technique to concisely achieve the same result?
I'm half expecting there to be a Javascript library out there that copies all the attributes.
Same style = css
Same attributes, values, etc = JS
See this fiddle for an example to get you started or this code snippet...
The CSS
input {
width: 200px;
background-color: yellow;
}
The JS
var value = 'myval';
var disabled = 'disabled';
var myElements = document.getElementsByTagName('input');
for(var i = 0; i < myElements.length; i++){
myElements[i].value = value;
myElements[i].disabled = disabled;
}
Yes with CSS classes. Create a master class and then use the class="master" on all your elements.
However I think you'll find you don't really want to do this once you get into it. But it will be easy to change the class on the elements you want to change so it won't hurt you to get started this way.
You can read about CSS here: http://www.w3schools.com/css/ though there are better resources w3schools covers a lot of ground.
If you're interested in building a consistent feel to a site and don't mind using jquery (which I love!) then you should checkout the jquery UI themeroller:
http://jqueryui.com/themeroller/
I don't know if this is what you're referring to, but best bet is use a class on all the elements you want to style and behave the same.
E.g.
File: index.html
Awesome Link
<button class="master-class">Awesome Button</a>
File: style.css
.master-class {
color: black;
background: white;
more of your styles...
}
File: scripts.js
$(function() {
$(".master-class").click(function() {
alert("This is from one of the many elements with the class 'master-class'");
});
});
Team Treehouse is a great place to really learn all about everything web. I've been using them for a while even though I knew most of the stuff on there, but I always pick up a few new things. http://teamtreehouse.com/
W3Schools ( http://www.w3schools.com ) is also great. It's where I learnt a lot of stuff in the beginning.
There is also a large amount of podcasts and vodcasts out there to teach you too, just search iTunes for web design.
Is it possible to compute resulting css style on the element manually (without need to render it)?
Lets say I'm supposed to have an HTML structure:
<p style="some_style1">
<span style="some_style2">
<span style="some_style3">
TEXT
</span>
</span>
</p>
I know what are some_style1, some_style2, some_style3 in terms of JS object (for example i have data for each element like: {font: 'Times New Roman' 12px bold; text-align: center;})
I want to MANUALLY (without need to render in browser the whole structure) compute resulting style that will effect "TEXT".
What algorithm (or solution) should I use?
There exist browsers that don't need rendering in a window (headless browser). You can load a page and query what you want. It won't be easier than in a normal browser to obtain what you ask though.
JSCSSP is a CSS parser written in cross-browser JavaScript that could be a first step to achieve what you want from scratch or quite. Give it a stylesheet and it'll tell you what a browser would've parsed. You still must manage:
the DOM,
inheritance of styles,
determine which rules apply to a given element with or without class, id, attributes, siblings, etc
priorities of selectors
etc
Its author is D. Glazman, co-chairman of the W3C CSS group and developer of Kompozer, NVu and BlueGriffon so it should parse CSS as expected :)
The simplest thing I can think of is to wrap the whole thing in a a container that you set display: none on, and append it to the DOM. The browser won't render it, but you'll then be able to query the computed style.
Here's an example showing how jQuery can't find the style information when the structure isn't connected to the DOM, but when it is, it can:
jQuery(function($) {
// Disconnected structure
var x = $("<p style='color: red'><span style='padding: 2em'><span style='background-color: white'>TEXT</span></span></p>");
// Get the span
var y = x.find("span span");
// Show its computed color; will be blank
display("y.css('color'): " + y.css('color'));
// Create a hidden div and append the structure
var d = $("<div>");
d.hide();
d.append(x);
d.appendTo(document.body);
// Show the computed color now; show red
display("y.css('color'): " + y.css('color'));
// Detach it again
d.detach();
function display(msg) {
$("<p>").html(String(msg)).appendTo(document.body);
}
});
Live copy | source
I can't guarantee all values will be exactly right, you'll have to try it and see; browsers may defer calculating some things until/unless the container is visible. If you find that some properties you want aren't calculated yet, you may have to make the div visible, but off-page (position: absolute; left: -10000px);
I found some articles about this: Can jQuery get all styles applied to an element on Stackoverflow.
Also this one on quirksmode: Get Styles that shows the following function:
function getStyle(el,styleProp)
{
var x = document.getElementById(el);
if (x.currentStyle)
var y = x.currentStyle[styleProp];
else if (window.getComputedStyle)
var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
return y;
}
This allows you to query for style properties
Styles override each other in the order in which they're defined: So anything in some_style3 that overrides the same selector in some_style2, say, will do. Otherwise, it will just be a union of the sets of selectors.
EDIT Some selectors won't override, but instead act relatively on a previous definition, so you've got to be careful about that.
What I need is to iterate over the dom at some start element and then go through all elements below the start element.
Here is what I was doing so far.
function iterDomFromStartElem = function(startElem, callBackFunc) {
if (startElem !== null) {
var items = startElem.getElementsByTagName("*");
for (var i = 0; i < items.length; i++) {
callBackFunc(items[i]);
}
}
}
The reason why I need to iterate over the dom from some start element is because our team recently got a request to implement font resizing; however, we developed are site statically with font-size in many different places using pixels. I realize that the easier approach would be to refactor the existing code, set a static font size at the root of the page, and use em's/percentages else where, so that if the business owner wanted to have a resize control on the pages, all we would have to do is increase the font-size in one spot. This refactor would require many hours, and i have been tasked with this using the least amount of man hours.
So, then, I have a call back defined like so,
function resizeFont(startElem, scale) {
iterDomFromStartElem(startElem, function(node) {
// get current size of node, apply scale, increase font size
}
}
Using this raw javascript would work but i'm having trouble getting font-size if its declared inside a css class.
I know that jquery has a css property and if I had a jquery object I could do $(this).css(....), so,
when I call callBackFunc(items[i]), how can I convert the items[i] into a jquery object so that in my call back function, I can do node.css(......)?
I guess I could do $(items[i].id), perhaps that would be the simplest.
Is there an easier way with javascript to determine the font size even if that font size is declared in a css class and that css class is attached to the element?
Preface: I think you're better off fixing the problem properly. You might save an hour or two now by taking a shortcut, but it's likely to cost you in the long term.
But re your actual question:
how can I convert the items[i] into a jquery object so that in my call back function, I can do node.css(......)?
If you pass a raw DOM object into $(), jQuery will return a wrapper around it. You don't have to go via the ID.
You can also get a jQuery instance for all descendant elements of a given starting point, like this:
var x = $("#starting_point *");
...although you'd still end up creating a lot of temporary objects if you then looped through it, like this:
$("#starting_point *").each(function() {
// Here, `this` is the raw DOM element
});
Here's an example of looping all elements under a given starting point with jQuery, in this case showing their tag and id (if any) and turning them blue (live copy):
$("#start *").each(function() {
display(this.tagName + "#" + (this.id || "?"));
$(this).css("color", "blue");
});
Note I said under. If you also want to include #start, the selector changes to #start, #start *.
Here's a complete example of increasing the font size of elements starting with (and including) a given start point, where the font size is variously set by inline and stylesheet styles (live copy):
CSS:
.x13 {
font-size: 13px;
}
.x17 {
font-size: 17px;
}
.x20 {
font-size: 20px;
}
HTML:
<input type="button" id="btnBigger" value="Bigger">
<div id="start" class="x13">
This is in 13px
<p style="font-size: 15px">This is in 15px
<span class="x17">and this is 17px</span></p>
<ul>
<li id="the_list_item" style="10px">10px
<strong style="font-size: 8px">8px
<em class="x20">five</em>
</strong>
</li>
</ul>
</div>
JavaScript:
jQuery(function($) {
$("#btnBigger").click(function() {
$("#start, #start *").each(function() {
var $this = $(this),
fontSize = parseInt($this.css("font-size"), 10);
display("fontSize = " + fontSize);
$this.css("font-size", (fontSize + 2) + "px");
});
});
function display(msg) {
$("<p>").html(msg).appendTo(document.body);
}
});