A) Each client has one DNS server: the router's local IP address. The router runs dnsmasq or whatever to proxy the DNS requests.
B) Each client has one or more DNS servers, with the router's IP address not listed, or listed last.
If you set up B, I think most operating systems will usually use the servers in order, i.e. only fall back to the second (ISP) server if the primary (pi-hole) doesn't respond.
DNS Server 1 = Pi-Hole
DNS Server 2 = ISP DNS Service, OpenDNS, your router whatever
when pi-hole blocks the ad's DNS query, macOS will treat that as a DNS failure and use DNS Server 2 as a fallback. Resulting in the ad being shown.
Doing (A) was my first attempt and at least using a Ubiquiti router, if Pi-hole blocked a DNS query it would always fallback to the secondary DNS server. In my environment, the only way I was able to get pi-hole to work consistently was to set the pi-hole server as the only DNS server in the DHCP server.
My experience with OSX and Pi-Hole doesn't match your experience. There's a difference between appearing to be in a failure mode (i.e. timing out) and returning blocked (null/0.0.0.0) results.
I did go and test this now, and agree with you. On macOS I set my primary DNS to pi-hole and secondary to 8.8.8.8. running dig on api.segment.io (blocked on pi-hole by default), it resolved to 0.0.0.0 via pi-hole and did not try 8.8.8.8 on any attempt. So my earlier comment is incorrect above and setting a secondary DNS server as a back-up may work.
For the record I was assigning these DNS server IPs via docker compose. So perhaps that makes a difference.