Graeme Smith scored a half-century but fell late on as South Africa made a confident reply after dismissing Sri Lanka for 180 on the opening day of the first Test on Thursday.
Seam bowler Vernon Philander claimed five wickets for the hosts, who reached 90 for one at the close at Centurion.
South Africa captain Smith looked in fine form as he stroked seven fours in his 61 -- his 30th half-century in his 94th Test -- but played around a full delivery from Dilhara Fernando to be trapped lbw. Opening partner Jacques Rudolph was unbeaten on 27.
Sri Lanka's bowers were steady, but they struggled to obtain the same assistance the South Africans did, even though the home attack sprayed the ball around disconcertingly at times.
South Africa's much-vaunted attack were struggling in helpful conditions as Thilan Samaraweera and Angelo Mathews added 65 for the fifth wicket off just 80 balls.
The pair took Sri Lanka to 156 for four before Philander struck three times in four overs to complete his third five-wicket haul in three Tests.
Philander's destructive burst began with two wickets in successive deliveries, both given out on review, as Samaraweera (36) edged an excellent delivery that nipped away off the seam and Kaushal Silva was adjudged to have brushed the ball with his glove as it flew to wicketkeeper Mark Boucher down the leg side.
Thisara Perera took a single off the hat-trick ball, but only lasted until the next over when he failed to read an Imran Tahir googly and Jacques Kallis made a stunning reflex catch at slip as the edge bounced off Boucher's thigh.
Sri Lanka had lost three wickets in five balls to slump to 157 for seven and Philander struck again to have Mathews caught by Kallis for 38.
Philander made full use of the grass on the pitch to claim five for 53 in 13 overs.
Dale Steyn produced a couple of top-class away swingers to bowl Chanaka Welegedara (4) and Fernando (0) with successive deliveries, ending the Sri Lankan innings on the stroke of tea.
Steyn had earlier removed Tillakaratne Dilshan and Mahela Jayawardene, who edged a back-foot drive into the slips for 30, the fast bowler finishing with impressive figures of four for 18.
Captain Dilshan's rash shot gave Sri Lanka a poor start and they battled to 76 for three at lunch after being put into bat.
Dilshan, on six, tried to on-drive a swinging delivery from Steyn on the up and looped a catch to Philander at wide mid-on.
Former captain Kumar Sangakkara lasted just three balls before Philander made a delivery rear up and induced an edge to second slip.
Sri Lanka were reeling on 12 for two, but Tharanga Paranavitana and the experienced Jayawardene batted with intense concentration in a sensible third-wicket stand of 54.
Steyn's first wicket was his 250th in Tests, the 28-year-old reaching the landmark in his 49th game.
Only Dennis Lillee has taken 250 wickets in fewer Tests, the Australian fast bowler reaching the milestone in his 48th match.
Scoreboard
Sri Lanka (first innings):
T. Paranavitana b Philander 32
T. Dilshan c Philander b Steyn 6
K. Sangakkara c Kallis b Philander 1
M. Jayawardene c Smith b Steyn 30
T. Samaraweera c Boucher b Philander 36
A. Mathews c Kallis b Philander 38
K. Silva c Boucher b Philander 0
T. Perera c Kallis b Tahir 1
R. Herath not out 14
C. Welegedara b Steyn 4
D. Fernando b Steyn 0
Extras: (b-1, lb-7, w-4, nb-6) 18;
Total: (all out; 47.4 overs) 180;
Fall of wickets: 1-11, 2-12, 3-66, 4-91, 5-156, 6-156, 7-157, 8-175, 9-180;
Bowling: Steyn 10.4-3-18-4, Philander 13-2-53-5 (nb-3, w-2), Morkel 10-1-48-0 (nb-3, w-2), Kallis 8-2-31-0, Tahir 6-0-22-1.
South Africa (first innings):
J. Rudolph not out 27
G. Smith lbw b Fernando 61
D. Steyn not out 0
Extras: (nb-2) 2;
Total: (one wicket, 34 overs) 90;
Fall of wickets: 1-88;
Bowling: Welegedara 9-2-19-0 (nb-1), Perera 8-1-34-0, Mathews 3-2-4-0, Fernando 7-1-21-1 (nb-1), Dilshan 2-0-4-0, Herath 5-2-8-0.