Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss
Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Change a CSS style definition from an onclick() javascript command

56 views
Skip to first unread message

Janis Papanagnou

unread,
Jan 10, 2024, 7:42:32 AM1/10/24
to
In a HTML source I have a style definition, say

<style type="text/css">
img { max-width: 50px; }
</style>

and a lot of <img> elements (in a <table> in the <body> of the file).

I want to change the value of 'max-width' for all images, ideally just
by changing the _single_ CSS value in the <style> definition (if that
is possible). It shall be triggered by a click on a the table, say, by
something (informally and obviously incorrectly written) like

<table onclick="document.querySelector('img').style.maxWidth='100px'">

How would such a Javascript command look like to work correctly? (If
that is possible in the first place.) - Or better use other methods?
Or do I have to individually change each <img> separately, maybe?

Thanks.

Janis

Jukka K. Korpela

unread,
Jan 10, 2024, 3:30:49 PM1/10/24
to
Janis Papanagnou wrote:

> I want to change the value of 'max-width' for all images, ideally just
> by changing the _single_ CSS value in the <style> definition (if that
> is possible). It shall be triggered by a click on a the table, say, by
> something (informally and obviously incorrectly written) like
>
> <table onclick="document.querySelector('img').style.maxWidth='100px'">
>
> How would such a Javascript command look like to work correctly?

Your code is formally correct but does not do what you want. By
definition, querySelector() returns the first element that matches the
selector given as the argument. So the code changes the width property
of the first img element.

To change them all, use the querySelectorAll() function, which returns
the list of all elements that match the selector.
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll

You then need a little more code to iterate over that list, e.g.

<script>
function xpand() {
const images = document.querySelectorAll('img');
images.forEach((image) => {
image.style.maxWidth='100px'
})
}
</script>


<table onclick="xpand()">

Janis Papanagnou

unread,
Jan 10, 2024, 8:53:21 PM1/10/24
to
Ah, okay. And it works well. Thanks!

So I also assume from that that we can't just change the single
CSS style attribute definition by Javascript to change all the
<img> elements, and that this iteration over all <img>es is
unavoidable, probably because the <style> elements are just
accessed once before building the DOM, and only in the DOM we
can change the attribute values? - Is that assumption correct?

Janis

Jukka K. Korpela

unread,
Jan 11, 2024, 1:36:59 PM1/11/24
to
Janis Papanagnou wrote:

> So I also assume from that that we can't just change the single
> CSS style attribute definition by Javascript to change all the
> <img> elements,

We can. It's just not practical as a rule.

> and that this iteration over all <img>es is
> unavoidable,

Applying something to all img elements is essentially iterative anyway,
though the iterative process can be hidden syntactically.

> probably because the <style> elements are just
> accessed once before building the DOM, and only in the DOM we
> can change the attribute values? - Is that assumption correct?

It seems that changing the content of a <style> element with client-side
JavaScript changes the rendering. I haven’t checked what the “HTML
standard” says about it. Anyway, it’s clumsier. In JS, you can access
the <style> element as text, but there are no built−in tools for
operating on it structurally.

A very trivial example, based on the assumption that you just want to
replace the contents of the first <style> element with something else:

function chg() {
document.getElementsByTagName('style')[0].innerHTML =
'img { max-width: 100px; }';
}

Janis Papanagnou

unread,
Jan 12, 2024, 5:19:57 AM1/12/24
to
On 11.01.2024 19:36, Jukka K. Korpela wrote:
> Janis Papanagnou wrote:
>
>> So I also assume from that that we can't just change the single
>> CSS style attribute definition by Javascript to change all the
>> <img> elements,
>
> We can. It's just not practical as a rule.

The motivation for my question was that I naturally use a CSS style
definition to avoid specifying the specific attributes with every
single <img> individual attributes. My hope way that this simple
segregation of duties between CSS and HTML could be also reflected
in case of changes done through Javascript.

>
>> and that this iteration over all <img>es is
>> unavoidable,
>
> Applying something to all img elements is essentially iterative anyway,
> though the iterative process can be hidden syntactically.

Indeed I have not expected that the many attribute changes would
magically vanish, but that it's done implicitly by the browser's
rendering engine. If I switch to explicit DOM manipulations (with
the Javascript loop) this gets then explicit by the JS application.

In other words, I would have found it conceptionally cleaner, and
I could also have imagined that it might be a bit more performant
to let the rendering engine do the task (the loop) implicitly.

So far my thoughts.

>
>> probably because the <style> elements are just
>> accessed once before building the DOM, and only in the DOM we
>> can change the attribute values? - Is that assumption correct?
>
> It seems that changing the content of a <style> element with client-side
> JavaScript changes the rendering. I haven’t checked what the “HTML
> standard” says about it. Anyway, it’s clumsier. In JS, you can access
> the <style> element as text, but there are no built−in tools for
> operating on it structurally.
>
> A very trivial example, based on the assumption that you just want to
> replace the contents of the first <style> element with something else:
>
> function chg() {
> document.getElementsByTagName('style')[0].innerHTML =
> 'img { max-width: 100px; }';
> }

Yes, this is indeed quite an ugly construct. My hope was that the
attribute can be changed with cleaner syntax (as opposed to defining
a complete new string as innerHTML).

So if that's the other choice, I also prefer the explicit JS loop.
I'll stay with your previously suggested method.

The complete application (to toggle the image sizes) became

<script>
var w = [ 50, 75, 100 ];
var h = [ 30, 45, 60 ];
var size = 0;
function switch_size() {
const images = document.querySelectorAll('img');
size = (size+1)%3;
images.forEach((image) => {
image.style.maxWidth = w[size];
image.style.maxHeight = h[size];
})
}
</script>


Thanks for the insights and additional explanations that you provided!

Janis

Jonathan N. Little

unread,
Jan 19, 2024, 11:38:00 AM1/19/24
to
Janis Papanagnou wrote:
> On 11.01.2024 19:36, Jukka K. Korpela wrote:
>> Janis Papanagnou wrote:
>>
>>> So I also assume from that that we can't just change the single
>>> CSS style attribute definition by Javascript to change all the
>>> <img> elements,
>>
>> We can. It's just not practical as a rule.
>
> The motivation for my question was that I naturally use a CSS style
> definition to avoid specifying the specific attributes with every
> single <img> individual attributes. My hope way that this simple
> segregation of duties between CSS and HTML could be also reflected
> in case of changes done through Javascript.
>
>>
>>> and that this iteration over all <img>es is
>>> unavoidable,
>>

No not really. Here is one way:
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">

<title>Change the container</title>

<style>
.small img {
max-width: 50px;
}

.medium img {
max-width: 100px;
}

.large img {
max-width: 150px;
}
</style>
</head>

<body>

<table id="image_container" class="small">
<tr>
<td><img src="sample.jpg" alt="sample"></td>
</tr>
<tr>
<td><img src="sample.jpg" alt="sample"></td>
</tr>
<tr>
<td><img src="sample.jpg" alt="sample"></td>
</tr>
<tr>
<td><img src="sample.jpg" alt="sample"></td>
</tr>
<tr>
<td><img src="sample.jpg" alt="sample"></td>
</tr>
</table>

<script>
let state = 0;
const sizes = ['small', 'medium', 'large'];
const last = 3
const container = document.getElementById('image_container');

function resize() {
const pointer = (++state) % last;
container.className = sizes[pointer];
}

container.addEventListener('click', resize);
</script>
</body>

</html>




Take care,

Jonathan
-------------------
LITTLE WORKS STUDIO
http://www.LittleWorksStudio.com

Janis Papanagnou

unread,
Jan 21, 2024, 4:01:50 AM1/21/24
to
On 19.01.2024 17:37, Jonathan N. Little wrote:
> Janis Papanagnou wrote:
>> On 11.01.2024 19:36, Jukka K. Korpela wrote:
>>> Janis Papanagnou wrote:
>>>
>>>> So I also assume from that that we can't just change the single
>>>> CSS style attribute definition by Javascript to change all the
>>>> <img> elements,
>>>
>>> We can. It's just not practical as a rule.
>>
>> The motivation for my question was that I naturally use a CSS style
>> definition to avoid specifying the specific attributes with every
>> single <img> individual attributes. My hope way that this simple
>> segregation of duties between CSS and HTML could be also reflected
>> in case of changes done through Javascript.
>>
>>>
>>>> and that this iteration over all <img>es is
>>>> unavoidable,
>>>
>
> No not really. Here is one way:

Thanks for this variant and for the code sample! - It's actually
how I hoped to be able to change all the sizes by changing one
property.

I have two questions on that variant, a technical and a design
question...

First; initially I had problems incorporating that pattern into
my code. I got a null pointer error with this part:
const container = document.getElementById('image_container');
The reason was probably because I'm used to collect JS <script>
code at the beginning of the HTML files in the <head> section.
After relocating it to the end of the <body> it seemed to work.
Is this script code placement mandatory (to make that pattern
work) or is there some way to keep it at the top of the HTML
file?
Previously I had the getElementById() call within the function
so that it was non-null when called; the disadvantage was that
it's called with every click. (Not really an issue since it's
not time critical as it's called once and only during a slow
user interaction.)

And second; is there some kind of design convention what sort
of solution is preferable; iteration over all images, or change
of the class attribute (with one static getElementById()), or
change of the class attribute (with dynamic getElementById()?
I'm not sure whether there are such conventions; to me it seems
that there's so many different variants possible and used. But
sometimes there's some hidden advantages or caveats that I'm
not aware of (I have no deep insights in that matter), so I am
asking for insights and experiences.

Thanks.

Janis

Janis Papanagnou

unread,
Jan 21, 2024, 4:28:36 AM1/21/24
to
On 21.01.2024 10:01, Janis Papanagnou wrote:
> On 19.01.2024 17:37, Jonathan N. Little wrote:
>>
>> No not really. Here is one way:
>
> Thanks for this variant and for the code sample! - It's actually
> how I hoped to be able to change all the sizes by changing one
> property.

Based on Jonathan's suggestion my current version now looks like

...
.small img { max-width: 50px; max-height: 30px; }
.medium img { max-width: 75px; max-height: 45px; }
.large img { max-width:100px; max-height: 60px; }
</style>

<script>
const sizes = [ 'small', 'medium', 'large' ];
var size = 0;
function switch_size() {
size = (size+1)%3;
document.getElementById('images').className = sizes[size];
}
</script>
</head>

<body>
<table id="images" class="small" ... onclick="switch_size()">
...


Works nicely. :-)

Janis

Jonathan N. Little

unread,
Jan 21, 2024, 10:43:50 AM1/21/24
to
Yes, placement is important as written because you cannot select a dom
element BEFORE it is created. Sometimes it is better to put script at
the end, especially if script is elaborate and time expensive so it will
not delay the rendering of the page. You can get around this in order to
put script in header if you prefer by having an initiation function to
add click handler to 'image_container', and then attaching that
initialization function to the document onload event. That way the dom
is loaded before attaching the click handler. Your preference.

> Previously I had the getElementById() call within the function
> so that it was non-null when called; the disadvantage was that
> it's called with every click. (Not really an issue since it's
> not time critical as it's called once and only during a slow
> user interaction.)

Just did it for simplicity. You already had variables out of the scope
of the function to preserve the state of image size. Otherwise you'd
need to store values in custom properties added to 'image_container' dom
element. I have done it both ways. This is just more straight forward
and simpler.

>
> And second; is there some kind of design convention what sort
> of solution is preferable; iteration over all images, or change
> of the class attribute (with one static getElementById()), or
> change of the class attribute (with dynamic getElementById()?
> I'm not sure whether there are such conventions; to me it seems
> that there's so many different variants possible and used. But
> sometimes there's some hidden advantages or caveats that I'm
> not aware of (I have no deep insights in that matter), so I am
> asking for insights and experiences.

As always there is more than one way to do something. I did not do a
benchmarking on this, you are welcome to do it. Just on assumption, both
methods trigger browser re-layout event. I would guess that iterating
through the dom would add some addition time depending on the size of
the document. A faster way to enlarge images is with css "transform:
scale()"
<https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale>
which doesn't trigger re-layout. But that means the scaled element is
taken out of the layout, so is depends on your application and design.
(You often is it used on buttons and images with that expand and "pop"
off of the page effect)

<style>
/* also add animation effects, no javascript */
.pop {
transition: transform 1s;
}

.pop:hover {
transform: scale(1.5);
}
</style>

<p>This is an example <img class="pop" src="sample.jpg"> pop effect.</p>

--

Janis Papanagnou

unread,
Jan 21, 2024, 11:41:54 AM1/21/24
to
On 21.01.2024 16:43, Jonathan N. Little wrote:
> [...]

Thanks for your explanations!

Janis

0 new messages