A GIF is a stack of separate pictures; an MP4 stores only what changes between frames. This page decodes your GIF frame by frame, resamples its uneven delays to a steady frame rate, fills transparency, and encodes H.264 with your browser's own encoder into an MP4 it writes itself. Then it plays the result and compares it with the GIF.
GIF picks up to 256 exact colours per frame. H.264 stores brightness for every pixel but colour for each 2 × 2 block (4:2:0), and rounds everything a little. Gradients get smoother, while thin coloured lines and pixel art soften. This compares the same frame from the GIF and from the MP4 your browser just decoded, at 4×.
MP4 is the better file almost everywhere a video tag or a social upload works. These are the cases where it isn't, checked against what this page measured.
A GIF autoplays and loops on its own. A video does the same with four attributes: autoplay, loop, muted (browsers only autoplay silent video) and playsinline (otherwise iPhones go full-screen). The MP4 next to the GIF above is playing with exactly this markup. The GIF's own loop count can't be carried: MP4 has no loop field, so looping is the page's job.
<video src="bounce.mp4" autoplay loop muted playsinline width="200" height="150" aria-label="bounce animation"></video>