Chris’ Corner: Good & Useful Ideas

I was ogling the idea of Exit Animations recently, that is, a recent proposal for (something like) @exit-style which could allow us to animate elements as we remove them from the DOM. That is largely just a proposal at the moment, with many challenges ahead.

But there is new tech that helps with exit (and entrance!) animations right now (in Chrome, anyway). They are some relatively new things that, if you’re like me, don’t pop to mind immediately just yet when we’re in these DOM enter/exit situations. Una Kravets and Joey Arhar covered them in a great blog post back in August: Four new CSS features for smooth entry and exit animations. Allow me to summarize!

  1. If you’re using a @keyframes animation, you can now set the display property anywhere within it and it’ll flip at that keyframe. It didn’t use to be like this. Animations would immediately move the display property to the final value. This makes “exit” animations where the very last thing you do is set display: none, which removes the element from view and the accessibility tree, very possible with @keyframes.
  2. If you’re using transition, however, the display property still instantly flips to the final value. That is, unless you use the new transition-behavior: allow-discrete; property/value which flips it so that display changes at the end of a transition instead of the beginning.
  3. Those first two are pretty darn handy for exit animations (they don’t help with leaving-DOM situations, but are still “exits” of a sort). But for entrance or “starting” animations, when an element is added to the DOM, now we have @starting-style that allows us to set some styles which then immediately transition to the styles set on the element outside of that at-rule, assuming they are present.
  4. Common HTML elements that you can imagine having entrances and exists are <dialog> and any element behaving as a “popover” (like a menu or tooltip). These elements benefit from being magically transported to a “top layer”, meaning less fiddling with z-index and stacking context problems and such. But now, if you decide to animate the transitions in and out of visibility, in order to make that happen smoothly, you need to add a new keyword overlay to your transitions. Hey, sometimes you gotta do more work to have nice things.

And all of that doesn’t even get into View Transitions. View Transitions can actually help with “real” exit animations, so that’s worth a look if you’re in that situation. Una and Joey do cover that, so definitely dig into that blog post.


You know how some analytics tools can track clicks on outgoing links on websites? That always boggled my mind. In order for the analytics tool to know that, it needs to shoot that information to a server in the tiny split second of time before the website is gone and replaced with the new one at the link the user followed. I just assume that is fairly unreliable.

There is actually a web platform API that is specifically designed for this “just before a user leaves” situation: navigator.sendBeacon(). That’s nice to have, but you still have to call it, and call it at the right time. Erik Witt researched this in the blog post Unload Beacon Reliability: Benchmarking Strategies for Minimal Data Loss.

He compared calling sendBeacon in an event listener for unload, beforeunload, pagehide, and visibilitychange. I would have put my money on beforeunload, but that was by far the worst reporting only 37% of data reliably. The best of the four is visibilitychange at 90%. Erik also covers an experimental API in Chrome that is reporting 98% so check out the post for that (it also looks a bit easier to use).


Once in a while, I see an AI/LLM API example that I’m like OK fine that’s pretty clever. I thought that when reading Raymond Camden’s Can GenAI help you win in Vegas? As Raymond says, uh, no, it can’t, but it can help you make the best-possible decision at a game like Blackjack that has a reasonably complex decision tree.

Of course what you could/should do, if you were going to write software to help you with Blackjack, is have the software return the correct result from the data in that tree. But there is something more fun and futuristic about asking an LLM for the answer instead. Like talking to a computer in your ear.

I’m playing blackjack and the dealer has a six of diamonds showing. I’ve got a jack of clubs and a jack of hearts. Should I hit or should I stay?

You have 20, which is a good hand. The dealer has 16, which is below the average. If you hit, you risk getting a card that will bust you. So it’s better to stay and hope that the dealer busts.

Again this isn’t a good idea, because as Raymond struggled through the AI was more than happy to provided horrible answers, but there is something interesting about crafting the prompt to get the best results and getting the results in “plain language” way that feels less boring than coordinates off a chart.


A Discord I’m in was chatting it up the other day about a recent Kevin Powell video: A new approach to container and wrapper classes (he credits a handful of others). The idea was setting up a grid with columns like this:

.grid {
  display: grid;
  grid-template-columns:
    [full-width-start] minmax(var(--padding-inline), 1fr)
    [breakout-start] minmax(0, var(--breakout-size))
    [content-start] min(
      100% - (var(--padding-inline) * 2),
      var(--content-max-width)
    )
    [content-end]
    minmax(0, var(--breakout-size)) [breakout-end]
    minmax(var(--padding-inline), 1fr) [full-width-end];
}

Kinda complicated looking right? Broken down into steps it’s really not that bad, it’s mostly the naming-things that makes it look like a lot. But the real beauty of it is in the naming. With this in place, you can very easily place an item edge-to-edge on the grid by just calling grid-column: full-width;, but regular content is set in the middle. There are some nice details to pick up in the video. Perhaps the best of which is how you can set the content within a full-width container back to the same center content area by applying the exact same template columns to that container.


Anything layout-related that requires JavaScript I usually side-eye pretty hard. The idea of layout failing, or even shifting, when JavaScript loads (or doesn’t) just bothers me.

But sometimes, when the layout updating is entirely a bonus enhancement, I relent. I think I might be there with Yihui Xie’s idea for making elements “full width” (like the class names Kevin makes available in the section above).

The idea is that you can use a little bit of JavaScript to dynamically decide if an element should be full width or not. Here are the situations:

  1. Code blocks (<pre><code>).If the scrollWidth is greater than offsetWidth, it means the code block has a horizontal scrollbar, and we may want to make it full-width.
  2. Tables (<table>).If its offsetWidth is greater than its parent’s offsetWidth, it is too wide.
  3. Table of contents (an element that has the ID TableOfContents, e.g., <nav id="TableOfContents">).If any TOC item has multiple rectangles on the layout (getClientRects().length > 1), it means the item is wrapped, and the TOC may benefit from more space.

If the elements become full-width, great, it’s a likely enhancement, but if they don’t, it’s not a big deal.

Yihui Xie does the full-width-ing with a class like this:

.fullwidth {
  width: 100vw;
  margin-left: calc(50% - 50vw);
}

Which is also a classic technique, but I’d say isn’t quite as robust or flexible as the above techniques.


Say you wanted to track page views on a site, but very much want to avoid any bots. That is, anything requesting your site that isn’t a real life human user. Herman Martinus is trying that with his Bear blogging platform like this:

body:hover {
  border-image: url("/hit/{{ post.id }}/?ref={{ request.META.HTTP_REFERER }}");
}

Now, when a person hovers their cursor over the page (or scrolls on mobile) it triggers body:hover which calls the URL for the post hit. I don’t think any bots hover and instead just use JS to interact with the page, so I can, with reasonable certainty, assume that this is a human reader.

I then confirm the user-agent isn’t a bot (which isn’t perfect, but still something). I also extract the browser and platform from the user-agent string.

Perhaps not rigorous computer science but I bet it’s a lot more useful number than just a server side counter.

Inquiry Regarding Blog Page Rankings

I've been actively monitoring the performance of my blog pages, and I noticed that some of them have not been consistently ranking in the top 3, I aim to achieve a position within the top 3. I did every possible way of SEO to improve their rankings.

I would appreciate it if you could provide insights into the factors influencing these rankings. Your expertise and guidance in understanding how I can optimize my blog content for better visibility would be invaluable.

If there are specific strategies, keywords, or content improvements that you recommend, I am eager to implement them to enhance the ranking of my blog pages.

Unblock Your Software Engineers With Unblocked

Developers spend weeks or even months onboarding at a new company. Getting up to speed in a new codebase takes time. During this time, the developer will have many questions (as they should)! However, those questions interrupt other team members who must stop what they’re doing to provide answers.

Most engineering organizations face the dilemma of ensuring the new developer gets the support they need without slowing down the rest of the team too much.

5 Steps To Tame Unplanned Work

In an ideal world, there are no zero-day security patches that absolutely must be applied today. There are no system outages - shortage never becomes full; APIs don't stop accepting parameters they accepted yesterday, users don't call support desks with tricky problems and everyone else writes code as good as you do so there are no bugs.

Maybe one day, but until then, there is unplanned but urgent work. Whether you call it DevOps, support, maintenance, or some other euphemism, it is work that just appears and demands to be done. The problem is this work is highly disruptive and destroys the best-laid plans.

Integration of Big Data in Data Management

Charting the Intricacies of Merging Big Data with Traditional Data Management Systems

The dawn of the digital age has led to an exponential increase in data creation, pushing the boundaries of what traditional data management systems can handle. Just a decade ago, businesses could operate smoothly with relational databases and simple ETL processes. However, the tides have turned, and what we are dealing with now is a deluge of data that defies the very principles on which traditional data management systems were built.

In this new paradigm, big data — characterized by its high volume, velocity, and variety — has become the focal point of technological innovations. From e-commerce giants and global banks to healthcare organizations and even government agencies, big data is redefining how decisions are made and operations are conducted. The sheer potential of insights to be garnered is too significant to ignore.

Mastering Cloud Migration: Best Practices to Make it a Success

Cloud migration projects are picking up pace as top executives are pushing for more efficiency and cost savings. And it may be tempting to say that cloud is the answer and that it’s the way to go for everyone. It may be tempting, but it’s not quite true. Throughout my professional career as an engineer, I’ve seen different scenarios, from middle-size companies deciding to move to the cloud to enterprise-grade corporations making a choice in favor of on-prem infrastructure. And I know that path is anything but straightforward.

If your team is getting ready for cloud migration, this article will provide you with an actionable approach to the task at hand.

X86 Assembly Help_value265

Hi,
I'm transitioning to assembly, starting with processor 8086.
The attached code is Masm 5 compatible and is a step up from Hello World, which linked and ran okay.
An endless loop exists, giving credence to this note.
Any comments or suggestions to resolve it would be appreciated, thanks!

.model small
.stack 100h
.data

name_prompt         db 'Enter your first name: $'
user_input          db 11, 0 ; Buffer for user's name (up to 10 characters + 1 null terminator)
range_prompt        db 'Enter the range of numbers (e.g., 0 to 10): $'
range_input         db 5, 0 ; Buffer for user's range input (up to 4 characters + 1 null terminator)
lower_bound         dw 0 ; Lower bound of the range
upper_bound         dw 0 ; Upper bound of the range
operand1            dw 0 ; First operand for flash card
operand2            dw 0 ; Second operand for flash card
correct_answer      dw 0 ; Correct answer for flash card
user_answer         db 0 ; User's answer for flash card
correct_count       db 0 ; Counter for correct answers
flash_card_prompt   db 'Flash Card: $'
correct_msg         db 'Correct!', 0Dh, 0Ah, '$'
incorrect_msg       db 'Incorrect!', 0Dh, 0Ah, '$'
result_prompt       db 'Number of Correct Answers: $'
hello_msg           db 'Hello World',0Dh, 0Ah, '$'
debug_msg           db 'Debug: ', 0
debug_end_msg       db 'Debug: End of Execution', 0

.code

 print_number proc
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        ; Display a number
        mov bx, 10 ; Set divisor to 10

        print_digit:
            xor dx, dx ; Clear any previous remainder
            div bx ; Divide AX by 10, result in AX, remainder in DX
            push dx ; Push the remainder onto the stack
            inc dl ; Convert the remainder to ASCII
            add dl, '0'
            mov ah, 02h ; DOS print character function
            int 21h ; Call DOS interrupt

            pop dx ; Pop the remainder from the stack
            cmp ax, 0 ; Check if quotient is zero
            jnz print_digit ; If not, continue the loop
            ret
    print_number endp

    generate_random_number proc
        ; Seed the random number generator
        mov ah, 2Ch ; DOS get system time function
        int 21h ; Call DOS interrupt
        xor ah, ah ; Clear AH
        mov cx, dx ; Use CX as the seed for the random number generator

        ; Generate a random number in the range [lower_bound, upper_bound]
        mov ax, cx ; Use AX to store the random number
        sub ax, [lower_bound]
        inc ax

        ; Move the upper_bound value into a register (BX)
        mov bx, [upper_bound]
        xor dx, dx
        div bx ; Divide AX by BX, result in AX, remainder in DX
        add ax, [lower_bound]
        ret
    generate_random_number endp

    clear_keyboard_buffer proc
        ; Clear the keyboard buffer
        mov ah, 0Ch ; DOS flush keyboard buffer function
        int 21h ; Call DOS interrupt
        ret
    clear_keyboard_buffer endp

main proc
    mov ax, @data
    mov ds, ax
    mov es, ax
    mov ss, ax

    ; Display prompt for user's name
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 09h         ; DOS print string function
    mov dx, offset name_prompt ; Offset of the message
    int 21h             ; Call DOS interrupt

    ; Read user's first name
    mov ah, 0Ah         ; DOS buffered input function
    lea dx, user_input  ; DX points to the buffer for input
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    int 21h             ; Call DOS interrupt

    ; Clear the keyboard buffer
    call clear_keyboard_buffer

    ; Display prompt for the range of numbers
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 09h         ; DOS print string function
    mov dx, offset range_prompt ; Offset of the message
    int 21h             ; Call DOS interrupt

    ; Read lower bound of the range
    mov ah, 0Ah         ; DOS buffered input function
    lea dx, range_input ; DX points to the buffer for input
    int 21h             ; Call DOS interrupt

    ; Convert ASCII input to integer (lower bound)
    mov al, [range_input + 2] ; ASCII character
    sub al, '0'               ; Convert ASCII to integer
    mov bl, 10                ; Multiplier for tens place
    mul bl                    ; Multiply AL by BL, result in AX
    mov [lower_bound], ax     ; Store the result

    ; Debug print for lower bound
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 09h ; DOS print string function
    mov dx, offset range_prompt ; Prompt for debug print
    int 21h ; Call DOS interrupt

    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ax, [lower_bound] ; Load lower_bound into AX
    call print_number ; Display the lower bound
    mov ah, 09h ; DOS print string function
    mov dx, offset debug_msg ; Debug message
    int 21h ; Call DOS interrupt

    ; Read upper bound of the range
    mov ah, 0Ah         ; DOS buffered input function
    lea dx, range_input ; DX points to the buffer for input
    int 21h             ; Call DOS interrupt

    ; Convert ASCII input to integer (upper bound)
    mov al, [range_input + 3] ; ASCII character for tens place
    sub al, '0'
    mov bl, 10
    mul bl                    ; Multiply AL by BL, result in AX
    mov bh, 0                 ; Clear BH
    mov bl, [range_input + 2] ; ASCII character for units place
    sub bl, '0'               ; Convert ASCII to integer
    add ax, bx                ; Add to result (upper bound)
    mov [upper_bound], ax     ; Store the result

    ; Debug print for upper bound
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 09h ; DOS print string function
    mov dx, offset range_prompt ; Prompt for debug print
    int 21h ; Call DOS interrupt

    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ax, [upper_bound] ; Load upper_bound into AX
    call print_number ; Display the upper bound
    mov ah, 09h ; DOS print string function
    mov dx, offset debug_msg ; Debug message
    int 21h ; Call DOS interrupt

    ; Preserve dx before calling generate_random_number
    push dx

    ; Generate random numbers in the specified range
    call generate_random_number   ; Call the generate_random_number procedure
    mov [operand1], ax

    call generate_random_number   ; Call the generate_random_number procedure
    mov [operand2], ax

    ; Restore dx after generate_random_number
    pop dx

    ; Generate and display flash cards
    mov cx, 10 ; Number of flash cards

    flash_cards_loop:
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        ; Add debug print to check loop iteration
        mov ah, 09h ; DOS print string function
        mov dx, offset debug_msg
        int 21h ; Call DOS interrupt

        mov ax, cx
        call print_number ; Display loop iteration number

        ; Generate random numbers in the specified range
        call generate_random_number   ; Call the generate_random_number procedure
        mov [operand1], ax

        call generate_random_number   ; Call the generate_random_number procedure
        mov [operand2], ax

        ; Display flash card
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        mov ah, 09h ; DOS print string function
        mov dx, offset flash_card_prompt
        int 21h ; Call DOS interrupt

        ; Display the first operand
        mov ax, [operand1]
        call print_number ; Display the operand

        ; Display operator (+ or -)
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        mov ah, 02h ; DOS print character function
        mov dl, '+'
        int 21h ; Call DOS interrupt

        ; Display the second operand
        mov ax, [operand2]
        call print_number ; Display the operand

        ; Display equals sign
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        mov ah, 02h ; DOS print character function
        mov dl, '='
        int 21h ; Call DOS interrupt

        ; Display the second operand
        mov ax, [operand2]
        call print_number;Display operand A2102 SYMBOL NOT DEFINED

        ; Display equals sign
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        mov ah, 02h ; DOS print character function
        mov dl, '='
        int 21h ; Call DOS interrupt

        ; Read user's answer
        mov ah, 01h      ; DOS input character function
        int 21h          ; Call DOS interrupt
        sub al, '0'      ; Convert ASCII to integer
        mov bh, 0        ; Clear BH
        mov bX, [correct_answer];Load correct_answer into BL A2048 OP.MUST BE SAME SIZE

        ; Calculate the correct answer
        add bl, bh ; Clear high bits of BL
        cmp al, bl ; Compare AL with BL
        je  correct_answer_handler ; Jump if equal

        ; Display incorrect message
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        mov ah, 09h ; DOS print string function
        mov dx, offset incorrect_msg
        int 21h ; Call DOS interrupt
        jmp next_flash_card ; Jump to the next flash card

    correct_answer_handler:
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        ; Add debug print to check correct answer handling
        mov ah, 09h ; DOS print string function
        mov dx, offset debug_msg
        int 21h ; Call DOS interrupt

        mov dx, [correct_answer]
        call print_number ; Display correct answer

        ; Display correct message
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        mov ah, 09h ; DOS print string function
        mov dx, offset correct_msg
        int 21h ; Call DOS interrupt

        ; Increment correct answer count
        mov al, [correct_count] ; Load the byte value into AL
        inc al                  ; Increment AL
        mov [correct_count], al ; Store the result back in memory
    next_flash_card:
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        ; Add debug print to check loop termination
        mov ah, 09h ; DOS print string function
        mov dx, offset debug_msg
        int 21h ; Call DOS interrupt
        ; Move to the next flash card
        dec cx ; Decrement the loop counter
        jnz flash_cards_loop ; Jump if not zero
    ; Display the number of correct answers
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 09h ; DOS print string function
    mov dx, offset result_prompt
    int 21h ; Call DOS interrupt
    ; Display the number of correct answers
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 02h ; DOS print character function
    mov dl, [correct_count]
    add dl, '0'
    int 21h ; Call DOS interrupt
    ; Exit program
    mov ah, 4Ch ; DOS exit function
    int 21h ; Call DOS interrupt
main endp
END main
.text
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 09h ; DOS print string function
    mov dx, offset hello_msg
    int 21h ; Call DOS interrupt
    mov ah, 09h ; DOS print string function
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov dx, offset debug_end_msg ; Debug message
    int 21h ; Call DOS interrupt
    mov ah, 4Ch ; DOS exit function
    int 21h ; Call DOS interrupt