Another captain's innings from Sri Lanka's Angelo Mathews could not stop Dale Steyn bowling South Africa into a position of strength on day three of the first Test in Galle.
Having racked up 455 for nine declared over days one and two, the Proteas reduced the tourists to 283 for nine as Steyn claimed five for 50 on a pitch that did not offer any obvious assistance.
Upul Tharanga made a controlled 83 at the top of the innings, but it was the in-form Mathews who battled hardest to prevent his team being rolled over, making a fine 89.
Sri Lanka added nine to their overnight score of 30 without loss before Kaushal Silva was tempted into hooking Steyn only to be brilliantly caught by Vernon Philander.
Tharanga was looking solid and breezed to his half-century with two fours in three balls off the spin of JP Duminy, but soon after South Africa struck a crucial double blow.
First was Kumar Sangakkara, dragging a Morne Morkel short ball on to his own stumps, and then came Mahela Jayawardene, who was pinned lbw by a full delivery from Steyn in the last over before lunch.
The departure of both middle-order mainstays left the hosts on 104 for three, but a string of aggressive strokes from Tharanga and Lahiru Thirimanne against Imran Tahir got Sri Lanka going again after the break.
Tharanga had reached 83 when he misjudged a delivery from Duminy and was stumped by Quinton de Kock.
Mathews and Thirmanne took the score to 182 for four at tea but the latter fell for 38 chasing a wider, swinging ball from Steyn, who made short work of Dinesh Chandimal and Dilruwan Perera.
At 201 for seven, Mathews badly needed to produce another big innings and he did, counter-attacking brilliantly including five fours from a single Morkel over.
He continued taking the game to South Africa, striking 14 fours and a six off Duminy before Tahir bowled him playing a slog sweep.
Morkel gave his side the perfect end to the day by removing Suranga Lakmal with the final ball before stumps, with South Africa well on top heading into day four.