Why must I put the command read into a subshell while using pipeline [duplicate]

The command df . can show us which device we are on. For example,

me@ubuntu1804:~$ df .
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sdb1       61664044 8510340  49991644  15% /home

Now I want to get the string /dev/sdb1.

I tried like this but it didn’t work: df . | read a; read a b; echo "$a", this command gave me an empty output. But df . | (read a; read a b; echo "$a") will work as expected.

I’m kind of confused now.

I know that (read a; read a b; echo "$a") is a subshell, but I don’t know why I have to make a subshell here. As my understanding, x|y will redirect the output of x to the input of y. Why read a; read a b; echo $a can’t get the input but a subshell can?