std::atomic allocates the T object as a class member, so its internals can apply sufficient alignment.
It's not well-defined to point an atomic<T>* at an existing T object, although in many implementations it happens to work. That's the problem that std::atomic_ref<T> is designed to solve; doing atomic accesses on a plain T object that exists separately and which you might do some non-atomic accesses to in other phases of your program. Before C++20, the standard didn't provide a way to do that at all; that's why a programmer-visible requirement to align a plain T object yourself is new in C++20 if you want to use atomic_ref, like
alignas(std::atomic_ref<T>::required_alignment) T foo;
std::atomic_ref<T>::required_alignment will be equal to alignof(std::atomic<T>), even if alignof(T) is lower. At least in normal implementations.
Without std::atomic_ref, you could of course use the compiler-specific extensions like GNU C __atomic builtins on plain objects.
That's how std::atomic<T> and std::atomic_ref<T> are implemented in GCC / clang headers, rather than direct support in the compiler proper like with the C11 _Atomic keyword. (Which has to do its own over-alignment of things it's applied to. There was GCC bug 65146 for a while where _Atomic didn't force the alignment of int64_t even on 32-bit targets where it only had 4-byte alignment such as x86; it worked outside structs because GCC chose to align int64_t for performance, but was not actually atomic inside structs. G++'s std::atomic<> had fixed that bug earlier, in the <atomic> header, but C _Atomic is internal to the compiler.)