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

    From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to alt.html on Wed Jan 10 13:42:27 2024
    From Newsgroup: alt.html

    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
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Jukka K. Korpela@jukkakk@gmail.com to alt.html on Wed Jan 10 22:30:25 2024
    From Newsgroup: alt.html

    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()">

    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to alt.html on Thu Jan 11 02:53:17 2024
    From Newsgroup: alt.html

    On 10.01.2024 21:30, Jukka K. Korpela wrote:
    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()">


    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

    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Jukka K. Korpela@jukkakk@gmail.com to alt.html on Thu Jan 11 20:36:34 2024
    From Newsgroup: alt.html

    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 havenrCOt checked what the rCLHTML standardrCY says about it. Anyway, itrCOs clumsier. In JS, you can access
    the <style> element as text, but there are no builtreAin 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; }';
    }

    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to alt.html on Fri Jan 12 11:19:53 2024
    From Newsgroup: alt.html

    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 havenrCOt checked what the rCLHTML standardrCY says about it. Anyway, itrCOs clumsier. In JS, you can access
    the <style> element as text, but there are no builtreAin 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

    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Jonathan N. Little@lws4art@gmail.com to alt.html on Fri Jan 19 11:37:55 2024
    From Newsgroup: alt.html

    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
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to alt.html on Sun Jan 21 10:01:46 2024
    From Newsgroup: alt.html

    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


    <!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


    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to alt.html on Sun Jan 21 10:28:32 2024
    From Newsgroup: alt.html

    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

    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Jonathan N. Little@lws4art@gmail.com to alt.html on Sun Jan 21 10:43:46 2024
    From Newsgroup: alt.html

    Janis Papanagnou wrote:
    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?

    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>
    --
    Take care,

    Jonathan
    -------------------
    LITTLE WORKS STUDIO
    http://www.LittleWorksStudio.com
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to alt.html on Sun Jan 21 17:41:50 2024
    From Newsgroup: alt.html

    On 21.01.2024 16:43, Jonathan N. Little wrote:
    [...]

    Thanks for your explanations!

    Janis

    --- Synchronet 3.21d-Linux NewsLink 1.2