Construction of an object via std::initializer_list is no different than constructing an object from any other object. The std::initializer_list is not a mystical, phantasmal construct; it is a living, breathing C++ object (albeit a temporary one). As such, it obeys all the rules of regular living, breathing C++ objects.
Aggregate initialization can effectively elide the copy/moves because it's aggregate initialization, a purely compile-time construct. std::vector is many things; an aggregate and a purely compile-time construct are not among them. So, in order for it to initialize itself from what it is given, it must execute actual C++ code, not compile-time stuff. It must iterate over each element of the initializer_list and either copy those values or move them. And the latter is not possible, since std::initializer_list doesn't provide non-const access to its members.
Initializer list initialization is meant to look like aggregate initialization, not perform like it. That's the cost of having a runtime, dynamic abstraction like std::vector.