South Africa took three Sri Lankan wickets in three overs to finish in a strong position on the third day of the first Test on Friday.
Sri Lanka, needing 304 to win, were 83 for three at the close, 221 runs short of their target.
The tourists started their chase promisingly in Durban, with captain Dimuth Karunaratne and Lahiru Thirimanne putting on 42 for the first wicket but both openers were out in the space of five balls, to be followed shortly afterwards by Kusal Mendis.
Thirimanne fell for 21 to a sharp catch at second slip by South African captain Faf du Plessis when he edged an extravagant drive against Kagiso Rabada.
Karunaratne was out for 20 in the next over, leg before wicket to Vernon Philander for the second time in the match. As in the first innings it was a tight decision which Karunaratne reviewed. Replays showed it was "umpire's call" with the ball flicking the bails.
Duanne Olivier replaced Philander and struck with his fifth ball when Kusal Mendis flashed at a short ball and was caught behind for nought.
Oshada Fernando and Kusal Perera, both showing a willingness to go for their shots, saw Sri Lanka through to an early close when bad light stopped play.
The flurry of wickets negated Sri Lanka's achievement in taking the last five South African wickets for eight runs.
Left-arm spinner Lasith Embuldeniya, 22, playing in his first Test, took five for 66 as South Africa were bowled out for 259 in their second innings.
South Africa were on course to set the tourists a more challenging target when they reached 251 for five, with captain Du Plessis and Philander looking solid in a sixth wicket partnership of 60.
But Embuldeniya, who bowled with impressive control, took Philander's wicket to start a collapse in which the last five wickets fell for eight runs.
Left-arm swing bowler Vishwa Fernando dismissed Du Plessis for 90 three overs later and the rest of the batting crumbled.
Fernando took four for 71 to follow up a career-best four for 62 in the first innings.
Du Plessis played a solid innings, facing 182 balls and hitting 11 fours before he padded up to a ball from Fernando which swung in and trapped him palpably in front of his stumps.
Du Plessis and Quinton de Kock (55) put on 96 for the fifth wicket with De Kock in sparkling form in a 62-ball innings before he went back on his stumps to Embuldeniya and was leg before to a ball which spun in to the left-hander and kept low.