It's the shell that sets the pipeline up. less is not involved in that.
When you do ls | less, the shell starts ls and less concurrently after having made the stdout of the process that will eventually execute ls the writing end of a pipe and the stdin of the one that will execute less the reading end of that same pipe.
ls detects that its stdout is not a tty device, and alters its behaviour accordingly. There's nothing that less can do about it.
What the shell could do is use a pseudo-terminal pair instead of a pipe to connect the two processes, but that would be a bad idea, as pseudo-terminals were not designed for that. For one, the tearing down of the connection would be problematic. less would probably be confused if its stdin was a pseudo-terminal master.
Another approach would be to get a 3rd process that reads the output of ls via a pseudo-terminal pair and feeds it to less via a pipe like with @JdeBP's ptyrun or ptybandage, or expect's unbuffer or using zsh's zpty builtin:
zmodload zsh/zpty
ttypager() { (zpty c "stty raw -echo; ${(q)@}"; zpty -r c) | less -RFX; }
ttypager ls
ls would run in a new session in a new terminal, so would not receive SIGINT when you press ^C, or SIGPIPE when you quit less before it finishes writing. However, since the process holding the master side (a subshell here) would still in those cases, ls would receive a SIGHUP and die nonetheless.
zpty here runs the command as if using eval, so aliases are going to be expanded. Actually, they would be expanded even if you called ttypager \ls as ttypager would still receive ls as argument and perform the alias expansion later.
Also note that both stdout and stderr would go to that pseudo-terminal and eventually to the pipe.
That's still a bit of a dirty hack. Here, the simplest would be to tell ls to behave as if it was connected to a terminal.
You could use a helper function like:
paged_ls() { ls -C --color=always "$@" | less -RFX; }
Where -C forces the output in column (which some implementations including GNU ls do by default when the output goes to a terminal) and --color=always force the output in colour regardless of whether the output goes to a terminal or not.