Horvat, Josh Leivo and Brock Boeser scored for the Canucks (25-24-7), who ended a three-game losing streak.
"Points are going to be hard to come by," Markstrom said. "We've got to battle hard for 65-plus minutes and we did it tonight, which is a nice win."
Elias Lindholm, Sam Bennett and Andrew Mangiapane scored, and David Rittich made 22 saves for the Flames (34-15-6), who had a season-high 47 shots.
Calgary has lost consecutive games for the first time since Dec. 20-22.
"[Markstrom] made some big saves. Right to the last buzzer we were getting looks in tight," Calgary defenseman Mark Giordano said. "Any game where you put up that many shots and get some looks you are not too disappointed."
Horvat gave the Canucks a 1-0 lead 44 seconds into the first period. He took a backdoor pass at the bottom of the left face-off circle and shot over Rittich's blocker for his second goal in 18 games.
Lindholm tied it 1-1 at 6:39 after being left unchecked at the top of the crease for a Monahan pass from below the goal line.
Leivo put Vancouver ahead 2-1 at 12:58 off the rush, cutting in the middle and using Boeser as a screen to shoot through the legs of Rittich from between the top of the face-off circles.
Bennett tied it 2-2 37 seconds later on a rebound after Markstrom couldn't control a bouncing shot.
"They came out with a lot of purpose, but we answered right back," Giordano said.
Calgary dominated the second period, getting the first 13 shots and going ahead 3-2 when Mangiapane scored on the Flames 17th shot for his first NHL goal at 13:19. It was his 27th NHL game.
"It was a little longer than I would have liked but I felt our line was hemming them in there," Mangiapane said.
Noah Hanafin intercepted a clearing attempt at the blue line after a long shift in the Vancouver end and passed cross-ice to Mangiapane at the right face-off dot for a one-timer before Markstrom could get across his crease.
"It was definitely a good feeling and nice to get it out of the way," Mangiapane said. "I would have taken it if it went off my shin pad but definitely nice and a nice pass."
Boeser tied it 3-3 at 15:11 with a wrist shot from the left face-off dot after a cross-ice pass from Pettersson.
"I really liked our second period," Calgary coach Bill Peters said. "We needed to come of that one with a lead and we didn't. But I liked a lot of the things we did here."